x86 Assembler using MASM32 Tutorial 13 - A Simple Window



Watch the video or follow the tutorial.



In this tutorial we will create an app that has a window, nothing extravagant, no buttons or controls just a simple window that is displayed then closed. We will do this entirely in code, no adding a window object though the VisualMASM interface. So, first of all open Visual MASM, if you haven't installed Visual MASM yet you can learn how to do it here. Once installed open it and learn create the default code template needed for all my tutorials here. This default code will be the starting point for most of our tutorials including this one. So, once all this is done you should be looking at the code window as seen below:



Scroll down to the .data section and add the following variables:

ClassName DB "SimpleWinClass", 0
AppName DB "Our First Window", 0


Then scroll down to the uninitialised data section which starts with .data? and add the following code:

hInstance HINSTANCE ?
CommandLine LPSTR ?

In the .code section after start: the following code should be added

; Get the handle to our program
Push NULL
Call GetModuleHandle

; Resulting memory address from GetModuleHandle call is loaded into Eax register, load it into hInstance variable
Mov hInstance, Eax

; Get command line parameters, there are none for our program but this info is used in call to WinMain
Call GetCommandLine
Mov CommandLine, Eax

; Push WinMain parameters onto stack and call
Push SW_SHOWDEFAULT
Push CommandLine
Push NULL
Push hInstance
Call WinMain

; WinMain complete so exit app
Push Eax
Call ExitProcess

; The procedure definition for the function WinMain
WinMain proc hInst:HINSTANCE, hPrevInst:HINSTANCE, CmdLine:LPSTR, CmdShow:DWORD

; Three local variables, first a window object, second a message object so the program can receive messages from the window and third a handle to the window
LOCAL wc:WNDCLASSEX
LOCAL msg:MSG
LOCAL hwnd:HWND

; Now we configure the various properties of the window object
Mov wc.cbSize, SIZEOF WNDCLASSEX
Mov wc.style, CS_HREDRAW Or CS_VREDRAW
Mov wc.lpfnWndProc, OFFSET WinProc
Mov wc.cbClsExtra, NULL
Mov wc.cbWndExtra, NULL
Push hInstance
Pop wc.hInstance
Mov wc.hbrBackground, COLOR_WINDOW + 1
Mov wc.lpszMenuName, NULL
Mov wc.lpszClassName, OFFSET ClassName

; Get default system Icon
Push IDI_APPLICATION
Push NULL
Call LoadIcon

; Load icon address into window object wc
Mov wc.hIcon, Eax
Mov wc.hIconSm, Eax

; Get default system cursor Push IDC_ARROW
Push NULL
Call LoadCursor

; Load system cursor into window object
Mov wc.hCursor, Eax

; Load window object into Eax and register window object
Lea Eax , wc
Push Eax
Call RegisterClassEx

; Create window now
Push NULL
Push hInst
Push NULL
Push NULL
Push CW_USEDEFAULT
Push CW_USEDEFAULT
Push CW_USEDEFAULT
Push CW_USEDEFAULT
Push WS_OVERLAPPEDWINDOW
Push OFFSET AppName
Push OFFSET ClassName
Push NULL
Call CreateWindowEx

; Load handle of newly created window into window handle variable
Mov hwnd, Eax

; Show complete window
Push CmdShow
Push hwnd
Call ShowWindow

; Update window
Push hwnd
Call UpdateWindow

; Enter a while loop that waits for and responds to messages sent to and from the window such as keyboard input
.WHILE TRUE

; Get any message from window, keystrokes and stuff
Push 0
Push 0
Push NULL
Lea Eax, msg
Push Eax
Call GetMessage

.BREAK .IF (!Eax)

; Understand received message
Lea Eax, msg
Push Eax
Call TranslateMessage

; Send message to program
Lea Eax, msg
Push Eax
Call DispatchMessage

.ENDW

; Load funcit0on return code into eax and return
Mov Eax, msg.wParam
Ret

WinMain endp

; The procedure definition for the function WinMain
WinProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM

; WndProc runs as part of GetMessage call
.IF uMsg==WM_DESTROY

Push NULL
Call PostQuitMessage

.ELSE

Push lParam
Push wParam
Push uMsg
Push hWnd
Call DefWindowProc

Ret

.ENDIF

Xor Eax, Eax
Ret

WinProc endp


The first part of the code before the call to ExitProcess simply prepares the call to WinMain and then calls it. There are no command line arguments for this program but if there were then they would be passed to WinMain as a parameter. The actual WinMain function is where the main code runs. The window object wc is instantiated as an instance of the window class WndClassEx and is then configured. The wc object is then registered, created and shown in that order and finally the UpdateWindow function is called to check for any user input or other messages that the window has to process. lastly in the WinMain function we enter a While loop that is how we check for messages. In this loop the messages received by the window are received, deciphered and processed and the appropriate action is then taken.

As part of the GetMessage call in the WinMain While loop the WndProc function runs which is part of the processing of the messages. It separates the messages into two types. WM_DESTROY which tells the window to close and will occur when the user exits the app and any other message.

The entire code looks like this:

; *************************************************************************
; 32-bit Windows Program
; *************************************************************************

.686                                      ; Enable 80686+ instruction set
.model flat, stdcall                ; Flat, 32-bit memory model (not used in 64-bit)
option casemap: none         ; Case sensitive syntax

; *************************************************************************
; MASM32 proto types for Win32 functions and structures
; *************************************************************************
include c:\masm32\include\windows.inc
include c:\masm32\include\user32.inc
include c:\masm32\include\kernel32.inc
include c:\masm32\include\masm32rt.inc     ; for using ustr$() and such like

; *************************************************************************
; MASM32 object libraries
; *************************************************************************
includelib c:\masm32\lib\user32.lib
includelib c:\masm32\lib\kernel32.lib

; *************************************************************************
; Our data section.
; *************************************************************************
.data

    ClassName DB "SimpleWinClass", 0
    AppName DB "Our First Window", 0

; *************************************************************************
; Our unintialised data section.
; *************************************************************************
.data?

    hInstance HINSTANCE ?
    CommandLine LPSTR ?

; *************************************************************************
; Our constant section.
; *************************************************************************
.const



; *************************************************************************
; Macros
; *************************************************************************



; *************************************************************************
; Our executable assembly code starts here in the .code section
; *************************************************************************
.code

start:

    ; Get the handle to our program
    Push NULL
    Call GetModuleHandle

    ; Resulting memory address from GetModuleHandle call is loaded into Eax register, load it into hInstance variable
    Mov hInstance, Eax

    ; Get command line parameters, there are none four our program but this info is used in call to WinMain
    Call GetCommandLine
    Mov CommandLine, Eax

    ; Push WinMain parameters onto stack and call
    Push SW_SHOWDEFAULT
    Push CommandLine
    Push NULL
    Push hInstance
    Call WinMain

    ; WinMain complete no exit app
    Push Eax
    Call ExitProcess

    ; The procedure definition for the function WinMain
WinMain proc hInst:HINSTANCE, hPrevInst:HINSTANCE, CmdLine:LPSTR, CmdShow:DWORD

    ; Three local variables, first a window object, second a message object so the program can receive message from the window and third a handle to the window
    LOCAL wc:WNDCLASSEX
    LOCAL msg:MSG
    LOCAL hwnd:HWND

    ; Now we configure the various properties of the window object
    Mov wc.cbSize, SIZEOF WNDCLASSEX
    Mov wc.style, CS_HREDRAW Or CS_VREDRAW
    Mov wc.lpfnWndProc, OFFSET WinProc
    Mov wc.cbClsExtra, NULL
    Mov wc.cbWndExtra, NULL
    Push hInstance
    Pop wc.hInstance
    Mov wc.hbrBackground, COLOR_WINDOW + 1
    Mov wc.lpszMenuName, NULL
    Mov wc.lpszClassName, OFFSET ClassName

    ; Get default system Icon
    Push IDI_APPLICATION
    Push NULL
    Call LoadIcon

; Load icon address into window object
    Mov wc.hIcon, Eax
    Mov wc.hIconSm, Eax

    ; Get default system cursor
    Push IDC_ARROW
    Push NULL
    Call LoadCursor

; Load system cursor address into window object
    Mov wc.hCursor, Eax

    ; Load window object into Eax and register window object
    Lea Eax , wc
    Push Eax
    Call RegisterClassEx

    ; Create window now
    Push NULL
    Push hInst
    Push NULL
    Push NULL
    Push CW_USEDEFAULT
    Push CW_USEDEFAULT
    Push CW_USEDEFAULT
    Push CW_USEDEFAULT
    Push WS_OVERLAPPEDWINDOW
    Push OFFSET AppName
    Push OFFSET ClassName
    Push NULL
    Call CreateWindowEx

    ; Load handle of newly created window into window handle variable
    Mov hwnd, Eax

    ; Show complete window
    Push CmdShow
    Push hwnd
    Call ShowWindow

    ; Update window
    Push hwnd
    Call UpdateWindow

        ; Enter a while loop that waits for and responds to messages sent to and from the window such as keyboard input
        .WHILE TRUE

            ; Get any message from window, keystrokes and stuff
            Push 0
            Push 0
            Push NULL
            Lea Eax, msg
            Push Eax
            Call GetMessage

            .BREAK .IF (!Eax)

            ; Understand received message
            Lea Eax, msg
            Push Eax
            Call TranslateMessage

            ; Send message to program
            Lea Eax, msg
            Push Eax
            Call DispatchMessage

        .ENDW

    ; Load funcit0on return code into eax and return
    Mov Eax, msg.wParam
    Ret

WinMain endp

; The procedure definition for the function WinMain
WinProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM

    ; WndProc runs as part of GetMessage call
    .IF uMsg==WM_DESTROY

        Push NULL
        Call PostQuitMessage

    .ELSE

        Push lParam
        Push wParam
        Push uMsg
        Push hWnd
        Call DefWindowProc

        Ret

    .ENDIF

    Xor Eax, Eax
    Ret

WinProc endp

end start


When you run the program a window will be displayed, close the window when you are finished.

Thank you for following this tutorial, I hope you found it useful. In the next tutorial we will add a text box and button to our window, so until then, enjoy.


Link to a text file with complete source code and more comments - here.