Calling API Functions

To begin with, consider how to call API functions. You can open the help file and choose any API function; for now, choose MessageBox:

 int MessageBox(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType); 

This function displays a message box with one or more command buttons that allow you to close it:

  • hWnd The descriptor (handle) of the message box window.

  • lpText The text that will be displayed in this message box.

  • lpCaption The window header text.

  • uType The window type; in particular, it allows you to define the number of command buttons.

Now, consider the parameter types. All parameters are 32-bit integer numbers :

  • HWND 32-bit integer

  • LPCTSTR 32-bit pointer to the string

  • UINT 32-bit integer

For a reason that will be explained later, you will have to add the A suffix to function names . Besides this, when using MASM, it is necessary to add the @16 suffix to the function names. Thus, the call to the previously described function will look as follows :

 CALL MessageBoxA@16 

What about parameters? They must have been loaded beforehand into the stack using PUSH commands. Memorize a simple rule: from left to right, and from bottom to top. Thus, assume that the window descriptor is located by the address HW , the strings are located by the addresses STR1 and STR2 , and the message box type is a constant. The simplest type has the zero value and is called MB_OK. Thus, you'll have the following:

 MB_OK equ 0 . . STR1      DB "Invalid entry! ", 0 STR2      DB "Error message.", 0 HW        DWORD ? . . PUSH      MB_OK PUSH      OFFSET STR1 PUSH      OFFSET STR2 PUSH      HW CALL      MessageBoxA@16 

As you can see, everything is easy and straightforward, as if you were calling this function from a program written in C or Pascal. The result returned by any function is usually an integer number returned into the EAX register.

Strings deserve to be considered separately. Generally, when speaking about strings, one usually means a string address (or pointer). In most cases, it is assumed that the string is terminated by the character with the code 0. However, one of the parameters of an API function often specifies the string length (in documentation often called the buffer) defined by another parameter. You should bear this in mind, because it might happen that the returned string won't be terminated by zero, and zero is required to use that string in another function. If this possibility is not taken into account, this might result in phantom errors in your program (i.e., such errors that appear or disappear like ghosts).

Note 

Microsoft declares that when returning from an API function, the registers EBX , EBP , ESP , ESI , and EDI must be preserved. The function value is normally returned into the EAX register. The contents of other registers are not guaranteed to be preserved.

C structures can be easily reproduced in Assembly language using a similar approach. For example, consider the following structure defining a system message:

 typedef struct tagMSG { //Msg        HWND hwnd;        UINT message;        WPARAM wParam;        LPARAM lParam;        DWORD time;        POINT pt; } MSG; 

This message, supplied with detailed comments, will appear in one of the examples provided later. In Assembly language, this structure will appear as follows:

 MSGSTRUCT STRUC           MSHWND    DD ?           MSMESSAGE DD ?           MSWPARAM  DD ?           MSLPARAM  DD ?           MSTIME    DD ?           MSPT      DD ?    MSGSTRUCT ENDS 

As you can see, in Assembly language everything looks even simpler. To tell the truth, the only thing difficult to understand is why Microsoft has muddled everything to such an extent with its attitude about variable types.

Note 

When calling an API function, an error can occur related either to invalid input parameters or to the impossibility of obtaining the desired results because of a specific system condition. In such cases, the contents returned in the EAX register serve as an indicator. Unfortunately, for different functions, these values might be different. Most frequently this is 0, but it also can be ˆ 1 or any other nonzero value. In this relationship, recall that 0 in most programming languages is the synonym of the FALSE value, and the true value is mapped to 1. In any particular case, I recommend that you consult the documentation. Using the GetLastError function, it is possible to get the code of the error that occurred last. This will explain why the API function couldn't complete successfully. Examples using the GetLastError function will be provided later. For decoding error codes, it is convenient to use the ERRLOOK.EXE program supplied as part of Microsoft Visual Studio.NET.



The Assembly Programming Master Book
The Assembly Programming Master Book
ISBN: 8170088178
EAN: 2147483647
Year: 2004
Pages: 140
Authors: Vlad Pirogov

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net