return-type function-name ( arg-type-1 arg-name-1, ... );
So, for example, the definition of SetWindowText looks like
BOOL SetWindowText ( HWND hWnd, LPCTSTR lpString );
In all cases, the arguments will be pushed starting with the rightmost argument. So to call the above function, you push the arguments before calling like this:
Push lpString
Push hWnd
Call SetWindowText
If you know what the types HWND and LPCTSTR mean, you will be able to convert the call to something like this:
push offset title1 ; address of new title string
push dword ptr [ebp+8] ; hwnd from wndproc arg list
call SetWindowText ; BOOL result (success/fail) in EAX
; arguments already popped by SetWindowText
The above illustrates the stdcall calling convention
used by most of the Win32 API functions. SetWindowText pops the
arguments so that you won't need to. If it had used the
cdecl calling convention, you would've needed to reset ESP
with an extra instruction, as in the following:
add esp,8 ; pop two DWORD arguments
Because SetWindowText uses a character string, the
documentation is actually referring to two functions:
SetWindowTextA, which uses a string of ANSI (8-bit) characters,
and SetWindowTextW, which uses a string of (wide 16-bit) Unicode
characters. In a C program, the include file windows.h has
macros that automatically control and redefine these documented
names to their Unicode/ANSI-specific ones. Thus the typical
program will use only the documented names.
SetWindowText equ <SetWindowTextA> ; use ANSI in Win95
You can, if you like, use a more elaborate technique to
select which name you want as default.
interface_pointer -> function ( arglist )
The arguments are pushed in the reverse order, just like SDK functions. The extra argument is the interface pointer which is pushed last. Then we use it to access the vtable and call the function. You will need to know the exact storage order of the function addresses. Assuming interface_pointer is in memory, the instructions would be something like
; ...
; insert argument stacking here
; ...
mov eax,[interface_pointer]
push eax ; push interface pointer
mov ecx,[eax] ; 1st dword of interface is vtable addr
call [ecx+8] ; call the third function
; arguments already popped
String data in COM interfaces should always be in
Unicode.
BYTE: char (signed), BYTE (unsigned)
WORD: short (signed), WORD (unsigned), ATOM (unsigned)
QWORD: double (floating point)
DWORD: int (signed), DWORD (unsigned), handles, pointers,
and hopefully everything else that's not a struct or
related to the previous types
push ebp
mov ebp,esp
sub esp,4 ; example for allocating one local DWORD
then you can access the first argument as [ebp+8], the second
argument as [ebp+12], and so on. The size of each argument is a
multiple of four bytes (DWORD). Most arguments are integers,
handles, or pointers: all of these are only one DWORD in size.
mov esp,ebp
pop ebp
The arguments can be popped off with the return instruction:
ret 16 ; example for four DWORD arguments