The Assembly Programming Master Book
| ||
| ||
|
Now, investigate the entire program structure. As I have already mentioned, in this chapter I describe the classical structure of a Windows application. In every program of this type, there is the main window and, consequently, the main window procedure. Generally, the following sections can be distinguished in the program code:
-
Window class registration
-
Creation of the main window
-
Message-processing loop
-
Main window procedure
Naturally, the program might have other sections. However, the listed sections are always present, and they make up the main program skeleton. Consider them one by one.
The Window Class Registration
Window class registration is carried out using the RegisterClassA function, which accepts the only parameterthe pointer to the WNDCLASS structure containing all information about the window (see the example later in this chapter).
Creating a Window
Based on the registered window class, it is possible to create an instance of the window using the CreateWindowExA (or CreateWindowA ) function. As can be easily noticed, this is similar to the object-oriented programming paradigm.
The Message-Processing Loop
Being written in C, this loop might appear as follows :
while (GetMessage (&msg, NULL, 0, 0)) { // Allow keyboard use by translating virtual key messages // into alphanumeric key messages TranslateMessage(&msg); // Return control to Windows and pass the message //to the window procedure DispatchMessage(&msg); }
The GetMessage() function "traps" the next message, pulling it from the message queue and placing it into the MSG structure. If there are no messages in the queue, the function waits for a message to arrive . Instead of the GetMessage function, the PostMessage with the same set of parameters is frequently used. The difference between GetMessage and PostMessage lies in that the latter does not wait for the message if there are no messages in the queue. The PostMessage function is often used to optimize program operation.
As relates to the TranslateMessage function, it covers the WM_KEYDOWN and WM_KEYUP messages, which are translated into WM_CHAR and WM_DEDCHAR and into WM_SYSKEYDOWN and WM_SYSKEYUP messages that are further converted into WM_SYSCHAR and WM_SYSDEADCHAR. The idea of translation isn't simple replacement. Rather, the function sends additional messages. For example, if you press and release an alphanumeric key, the window will first receive the WM_KEYDOWN message, the WM_KEYUP message will be the next, and the WM_CHAR message will be the last to arrive. As can be easily seen, the exit from the loop takes place only when the GetMessage function returns 0. This is possible only when the exit message arrives (the WM_QUIT message as shown in the example later in this chapter). Thus, the waiting loop plays a double role: First, the messages intended for a specific window are processed in a certain way, and second, the loop waits for the message instructing it to exit the program.
The Main Window Procedure
Here is the prototype of the window function [i] written in C:
LRESULT CALLBACK WindowFunc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
Leaving alone the type of the function's return value, [ii] pay special attention to the parameters passed to it. Here they are with brief explanations :
-
hwnd window identifier
-
message message identifier
wParam and lParam parameters clarifying the message goal (for each message, different parameters may play different roles or play no role at all)
As you probably have guessed, all four parameters are of the DWORD type.
And now, consider the "skeleton" of this function written in Assembly language.
Listing 2.1: The "skeleton" of window procedure
|
WNDPROC PROC PUSH EBP MOV EBP, ESP ; Now EBP points to the top of the stack PUSH EBX PUSH ESI PUSH EDI PUSH DWORD PTR [EBP+14H] ; LPARAM (lParam) PUSH DWORD PTR [EBP+10H] ; WPARAM (wParam) PUSH DWORD PTR [EBP+0CH] ; MES (message) PUSH DWORD PTR [EBP+08H] ; HWND (hwnd) CALL DefWindowProcA@16 POP EDI POP ESI POP EBX POP EBP RET 16 WNDPROC ENDP
|
Now, let me comment the fragment provided in Listing 2.1:
RET 16 Exit and pop four parameters from the stack (16 = 4 — 4)
Access to parameters is carried out using the EBP register:
DWORD PTR [EBP+14H] ; LPARAM (lParam) DWORD PTR [EBP+10H] ; WPARAM (wParam) DWORD PTR [EBP+0CH] ; MES (message) - Message code DWORD PTR [EBP+08H] ; -HWND (-hwnd) - Window descriptor
The DefwindowProc function is called for the messages that are not handled in the window function. As you can see in this example, no messages arriving to the window function are processed. I have guaranteed that the contents of the following four registers have been preserved: EBX , EBP , ESI , and EDI. This is a requirement specified in the documentation, although I usually try to guarantee that no registers change.
[i] I'd like to point out once again that in this book, the terms "procedure" and "function" are synonyms.
[ii] You'll never need it.
| ||
| ||
|