Tutorial 2. A Simple Window
Last updated: 4 January 2000
by Dolphinz

SUMMARY

This is my second tutorial about win32 programming, in assembly languaje, and this time cover about how to make our first simple window. The complete source code and program for this tutorial can be downloaded from here : Tutorial 2


THEORY

A window is created from a window class. The window class identify the window procedure which process all the messages to the window.

Before to create a window for our program, you have to register the window class using the function RegisterClassEx( ). This function requires only a paramenter: a pointer to a data structure of the type WNDCLASSEX. This structure is defined of the following way :

                 WNDCLASSEX   STRUCT
                   cbSize             DWORD  ?
                   style               DWORD  ? ; style of the window to create
                   lpfnWndProc      DWORD  ? ; it's procedure
                   cbClsExtra         DWORD  ?
                   cbWndExtra       DWORD  ?
                   hInstance          DWORD  ? ; a handle Instance
                   hIcon              DWORD  ? ; icon of the window
                   hCursor            DWORD  ? ; cursor of the window
                   hbrBackground    DWORD  ? ; brush for the background
                   lpszMenuName     DWORD  ? ; Menu resource, goes here
                   lpszClassName     DWORD  ? ; Class name of the window
                   hIconSm           DWORD  ?
                 WNDCLASSEX   ENDS
			
WNDCLASS Structure


The window class, defines several characteristics of the window, such as it's icon, it's cursor, it's color, it's procedure... Now, let me explain, some fields of this structure:

lpfnWndProc :
contains the address of the window procedure, that defines how windows of this class will behave.
hInstance :
contains the handle for the module that "owns" the window class. And remember that, a Instance or module handle are unique only for the current program.
hIcon :
contains the handle of the icon to be used by the window.
hCursor :
contains the handle of the cursor to be used by the window.
hbrBackground :
contains a handle to a brush to paint the window. Here you can use a bitmap to be set as the background.
lpszMenuName :
contains the address of a null terminated string, defining the menu resource. This must be the same as defined in the resource script file. You can also use a number defining a menu.
lpszClassName :
contains the address or a null-terminated string, which specifies the class of the window.

THE CODE

Now let's see the code for the second tutorial and look what has changed since last tutorial.
Now we are using more interesting functions and this is only the beginning...

.386p                      ; 80386 instruction set.
.model flat, stdcall       ; Memory model I will use.

; external API functions, we need
extrn           GetModuleHandle  : PROC
extrn           RegisterClassExA : PROC
...

.DATA

msg               MSG	    	<0>
wc                WNDCLASSEX  <0>

;========== Handles
hMain           dd      0  ; handle for the main window
hInst            dd      0  ; Instance handle

;========== Strings
szProgName      db      'Tutorial 2 - A Simple Window',0
szMainClass      db      'ASMWINDOW',0

.CODE
start:			           ; Entrypoint
    call    GetModuleHandleA, 0    ; Get the Instance handle(module handle)  
    mov     hInst, eax             ; save here

    mov     [wc.style], CS_HREDRAW + CS_VREDRAW
    mov     [wc.lpfnWndProc], offset WndProc
    mov     [wc.cbClsExtra], 0
    mov     [wc.cbWndExtra], 0

    mov     eax, [hInst]
    mov     [wc.hInstance], eax

    ; Load the icon for my application      
    call      LoadIconA, 0, IDI_APPLICATION
    mov      [wc.hIcon], eax        ; save here

    ; Load the cursor for my application
    call      LoadCursorA, 0, IDC_ARROW   
    mov     [wc.hCursor], eax      ;save here

    mov     [wc.hbrBackground], COLOR_WINDOW + 1
    mov     dword ptr [wc.lpszMenuName], 0
    mov     dword ptr [wc.lpszClassName], offset szMainClass
    push    offset wc
    call      RegisterClassExA
	


GetModuleHandle( ) : is the first function what I use in my program, this function returns the Instance handle of our program. The Instance handle is like the ID of our program.
Several win32 API functions use the Instance handle as a parameter.
RegisterClassExA( ) : is the second function I use in my program, which registers the window class, this is very important, because remember that if you want to create a window, you have to register it's class.

After registering our window class, we can create our window using CreateWindowExA( ) function, and note that this function has 12 parameters:

            call    CreateWindowExA, 0,\  <-Extra style of our window
                    offset szMainClass,\
                    offset szProgName,\
                    WS_VISIBLE OR WS_CAPTION OR WS_SYSMENU,\
                    100,\                     <- X position
                    50,\                      <- Y position
                    300,\                     <- width of the window
                    100,\                     <- height of the window
                    0,                         <- handle to parent's window if exists
                    0,                         <- handle to the window's menu
                    hInst,                     <- the instance handle
                    0                          <- lparam
            mov     hMain, eax               ; save handle of window


At this point, the window handle is stored in hMain, so I save it for later use. The window we just created is not automatically displayed, so we have to use ShowWindow( ) function, with the window handle, and the desired display mode as parameters.
After this, you can call the UpdateWindow( ) function, in order to repaint the client area, of the window.

            call    ShowWindow, hMain, SW_SHOWNORMAL
            call    UpdateWindow, hMain       


Now, our window is displayed on the screen, but we can't reveice input from it, so we have to accomplish this with a message loop.
The message loop, checks for the messages from windows, using the function GetMessageA( ).
TranslateMessage( ) is a function that takes keyboard input and generates new messages that are placed on the message queue. And the function DispatchMessageA( ) sends the message data to our window procedure.

msg_loop:
        call    GetMessageA, offset msg, 0, 0, 0
        cmp     ax, 0
        je      end_loop
        call    TranslateMessage, offset msg
        call    DispatchMessageA, offset msg
        jmp     msg_loop
end_loop:
        call    ExitProcess, 0


This code below, is the window procedure, that responds to each window message, and it's contained in the WndProc procedure.
The DefWindowProcA( ) is a API function that processes all the messages, that your program is not interested in.
The only one message that you must respond to is the WM_DESTROY message. This message is sent to your window procedure whenever your window is closed.

WndProc         proc    Hwnd:DWORD, wmsg:DWORD, wparam:DWORD, lparam:DWORD
        movzx   eax,    WORD PTR wmsg
        .if     eax == WM_DESTROY
                jmp     wmdestroy
        .else
                call    DefWindowProcA, Hwnd, wmsg, wparam, lparam
                jmp     @@End
        .endif
                xor     eax, eax
        @@End:
                ret
wmdestroy:
        call    PostQuitMessage, 0
        xor     eax, eax
        ret
WndProc         endp
public  WndProc


Well, this has been my second tutorial about win32asm programming, and we'll see in the next tutorial. Happy coding!...


Copyright © 1998, Dolphinz