You do not need to find the length of the string after the call to wsprintf
as it returns the number of characters copied to the buffer.
Next, there is what is called Application binary interface (ABI) which covers many details such as Calling Conventions
When you are dealing with the Windows API, or C runtimes, they follow these calling conventions, where esi
, edi
, ebx
, ebp
, and esp
are saved across the function call. Which means, if you have a value in one of those registers, then call an API function, that value will still be the same after the call.
eax
, ecx
, and edx
do not have to be saved, so anything you have in those registers before a call is NOT guaranteed to be the same. if you have something in those registers, and you need that value after a call, you need to save to a variable or the stack with push
eax
is used for return values.
That being said, in this sample, I use ebx
as the loop counter, and esi
as the current number to print, as those values will stay the same across API calls.
This is NASM, but it will give you and idea.
%include "externs.inc"
%define STD_OUTPUT_HANDLE -11
%define STD_INPUT_HANDLE - 10
%define NULL 0
SECTION .data
strFormat DB "Number %d ",13,10,0
SECTION .bss
buf resb 16
stdout resd 1
stdin resd 1
lpNumRead resd 1
inChar resb 1
global start2
SECTION .text
start2:
push STD_OUTPUT_HANDLE
call GetStdHandle
mov [stdout], eax
push STD_INPUT_HANDLE
call GetStdHandle
mov [stdin], eax
mov ebx, 10000
mov esi, 1
CountOut:
push esi
push strFormat
push buf
call wsprintf
add esp, 4 * 3
push NULL
push lpNumRead
push eax
push buf
push dword [stdout]
call WriteConsole
inc esi
dec ebx
jnz CountOut
push NULL
push lpNumRead
push 1
push inChar
push dword [stdin]
call ReadConsole
push 0
call ExitProcess