x86 Assembler using MASM32 Tutorial 14 - A Window with a TextBox and Button



Watch the video or follow the tutorial.



In this tutorial we will create an app that has a window and a text box and button. When you press the button it will display in a MessageBox the text that was in the text box. 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 "Button EditBox App", 0
MenuName DB "FirstMenu", 0
ButtonClassName DB "button", 0
ClearButtonClassName DB "button", 0
ClearButtontext DB "Press to Clear Text", 0
ButtonText DB "Press to Display Text", 0
EditClassName DB "edit", 0
TestString DB "Enter Text Here", 0


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

hInstance HINSTANCE ?
CommandLine LPSTR ?
hwndButton HWND ?
hwndClear HWND ?
hwndEdit HWND ?
buffer BYTE 512 DUP(?)

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

ButtonID Equ 1
EditID Equ 2
ClearButtonID Equ 3
IDM_HELLO Equ 1
IDM_CLEAR Equ 2
IDM_GETTEXT Equ 3

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

; Get the handle to our program
    ; 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 WndProc
    Mov wc.cbClsExtra, NULL
    Mov wc.cbWndExtra, NULL
    Push hInstance
    Pop wc.hInstance
    Mov wc.hbrBackground, COLOR_BTNFACE + 1
    Mov wc.lpszMenuName, OFFSET MenuName
    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 210
    Push 300
    Push CW_USEDEFAULT
    Push CW_USEDEFAULT
    Push WS_OVERLAPPEDWINDOW
    Push OFFSET AppName
    Push OFFSET ClassName
    Push WS_EX_CLIENTEDGE
    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 Ecx, msg
            Push Ecx
            Call GetMessage

            .BREAK .IF (!Eax)

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

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

        .ENDW

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

WinMain endp

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

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

        Push NULL
        Call PostQuitMessage

    .ELSEIF uMsg == WM_CREATE

        ; Create Edit Button now
        Push NULL
        Push hInstance
        Push EditID
        Push hWnd
        Push 25
        Push 200
        Push 35
        Push 40
        Push WS_CHILD Or WS_VISIBLE Or WS_BORDER Or ES_LEFT Or ES_AUTOHSCROLL
        Push NULL
        Push OFFSET EditClassName
        Push WS_EX_CLIENTEDGE
        Call CreateWindowEx

        Mov hwndEdit, Eax

        Push hwndEdit
        Call SetFocus

        ; Create display button now
        Push NULL
        Push hInstance
        Push ButtonID
        Push hWnd
        Push 25
        Push 200
        Push 70
        Push 40
        Push WS_CHILD Or WS_VISIBLE Or BS_DEFPUSHBUTTON
        Push OFFSET ButtonText
        Push OFFSET ButtonClassName
        Push NULL
        Call CreateWindowEx

        Mov hwndButton, Eax

        ; Create clear button now
        Push NULL
        Push hInstance
        Push ClearButtonID
        Push hWnd
        Push 25
        Push 200
        Push 100
        Push 40
        Push WS_CHILD Or WS_VISIBLE Or BS_DEFPUSHBUTTON
        Push OFFSET ClearButtonText
        Push OFFSET ClearButtonClassName
        Push NULL
        Call CreateWindowEx

        Mov hwndClear, Eax

        ; Set initial text box value
        Push 0
        Push IDM_HELLO
        Push WM_COMMAND
        Push hWnd
        Call SendMessage

    .ELSEIF uMsg == WM_COMMAND

        Mov Eax, wParam

        .IF lParam == 0

            ; AX = 2nd 2 bytes )bits 16 - 31) in Eax register
            .IF ax == IDM_HELLO

                Push OFFSET TestString
                Push hwndEdit
                Call SetWindowText

            ; Message to clear text box
            .ELSEIF ax == IDM_CLEAR

                Push NULL
                Push hwndEdit
                Call SetWindowText

            ; Message to get text from text box
            .ELSEIF ax == IDM_GETTEXT

                Push 512
                Push OFFSET buffer
                Push hwndEdit
                Call GetWindowText

                ; Message Box result
                Push MB_OK
                Push OFFSET AppName
                Push OFFSET buffer
                Push NULL
                Call MessageBox

            ; Any other message
            .ELSE

                Push hWnd
                Call DestroyWindow

            .ENDIF

            .ELSE


; If display button was pressed
        .IF ax == ButtonID

            Shr Eax , 16

            .IF ax == BN_CLICKED

                ; Set initial text box value
                Push 0
                Push IDM_GETTEXT
                Push WM_COMMAND
                Push hWnd
                Call SendMessage

            .ENDIF

        ; If display button was pressed
        .ELSEIF ax == ClearButtonID

            Shr Eax , 16

            .IF ax == BN_CLICKED

            ; Set initial text box value
            Push 0
            Push IDM_CLEAR
            Push WM_COMMAND
                Push hWnd
                Call SendMessage

            .ENDIF

        .ENDIF

        .ENDIF

    .ELSE

        Push lParam
        Push wParam
        Push uMsg
        Push hWnd
        Call DefWindowProc

        Ret

    .ENDIF

    Xor Eax, Eax

    Ret

WndProc endp


This app runs the same as the previous tutorial with the main window being registered, created and displayed within the WInMain function. The new code is the creation of the two buttons and edit box when the message sent to the main window is WM_CREATE, this happens when the application is started. The same section of code handles the pressing of the two buttons when the message sent is WM_GETTEXT and WM_CLEAR.

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

WinMain proto :DWORD,:DWORD,:DWORD,:DWORD

; *************************************************************************
; 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 "Button EditBox App", 0
    MenuName DB "FirstMenu", 0
    ButtonClassName DB "button", 0
    ClearButtonClassName DB "button", 0
    ClearButtonText DB "Press to Clear Text", 0
    ButtonText DB "Press to Display Text", 0
    EditClassName DB "edit", 0
    TestString DB "Enter Text Here", 0

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

    hInstance HINSTANCE ?
    CommandLine LPSTR ?
    hwndButton HWND ?
    hwndClear HWND ?
    hwndEdit HWND ?
    buffer DB 512 DUP(?)

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

    ButtonID Equ 1
    EditID Equ 2
    ClearButtonID Equ 3
    IDM_HELLO Equ 1
    IDM_CLEAR Equ 2
    IDM_GETTEXT Equ 3

; *************************************************************************
; 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 WndProc
    Mov wc.cbClsExtra, NULL
    Mov wc.cbWndExtra, NULL
    Push hInstance
    Pop wc.hInstance
    Mov wc.hbrBackground, COLOR_BTNFACE + 1
    Mov wc.lpszMenuName, OFFSET MenuName
    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 210
    Push 300
    Push CW_USEDEFAULT
    Push CW_USEDEFAULT
    Push WS_OVERLAPPEDWINDOW
    Push OFFSET AppName
    Push OFFSET ClassName
    Push WS_EX_CLIENTEDGE
    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 Ecx, msg
            Push Ecx
            Call GetMessage

            .BREAK .IF (!Eax)

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

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

        .ENDW

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

WinMain endp

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

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

        Push NULL
        Call PostQuitMessage

    .ELSEIF uMsg == WM_CREATE

        ; Create Edit Button now
        Push NULL
        Push hInstance
        Push EditID
        Push hWnd
        Push 25
        Push 200
        Push 35
        Push 40
        Push WS_CHILD Or WS_VISIBLE Or WS_BORDER Or ES_LEFT Or ES_AUTOHSCROLL
        Push NULL
        Push OFFSET EditClassName
        Push WS_EX_CLIENTEDGE
        Call CreateWindowEx

        Mov hwndEdit, Eax

        Push hwndEdit
        Call SetFocus

        ; Create display button now
        Push NULL
        Push hInstance
        Push ButtonID
        Push hWnd
        Push 25
        Push 200
        Push 70
        Push 40
        Push WS_CHILD Or WS_VISIBLE Or BS_DEFPUSHBUTTON
        Push OFFSET ButtonText
        Push OFFSET ButtonClassName
        Push NULL
        Call CreateWindowEx

        Mov hwndButton, Eax

        ; Create clear button now
        Push NULL
        Push hInstance
        Push ClearButtonID
        Push hWnd
        Push 25
        Push 200
        Push 100
        Push 40
        Push WS_CHILD Or WS_VISIBLE Or BS_DEFPUSHBUTTON
        Push OFFSET ClearButtonText
        Push OFFSET ClearButtonClassName
        Push NULL
        Call CreateWindowEx

        Mov hwndClear, Eax

        ; Set initial text box value
        Push 0
        Push IDM_HELLO
        Push WM_COMMAND
        Push hWnd
        Call SendMessage

    .ELSEIF uMsg == WM_COMMAND

        Mov Eax, wParam

        .IF lParam == 0

            ; AX = 2nd 2 bytes )bits 16 - 31) in Eax register
            .IF ax == IDM_HELLO

                Push OFFSET TestString
                Push hwndEdit
                Call SetWindowText

            ; Message to clear text box
            .ELSEIF ax == IDM_CLEAR

                Push NULL
                Push hwndEdit
                Call SetWindowText

            ; Message to get text from text box
            .ELSEIF ax == IDM_GETTEXT

                Push 512
                Push OFFSET buffer
                Push hwndEdit
                Call GetWindowText

                ; Message Box result
                Push MB_OK
                Push OFFSET AppName
                Push OFFSET buffer
                Push NULL
                Call MessageBox

            ; Any other message
            .ELSE

                Push hWnd
                Call DestroyWindow

            .ENDIF

            .ELSE


; If display button was pressed
        .IF ax == ButtonID

            Shr Eax , 16

            .IF ax == BN_CLICKED

                ; Set initial text box value
                Push 0
                Push IDM_GETTEXT
                Push WM_COMMAND
                Push hWnd
                Call SendMessage

            .ENDIF

        ; If display button was pressed
        .ELSEIF ax == ClearButtonID

            Shr Eax , 16

            .IF ax == BN_CLICKED

            ; Set initial text box value
            Push 0
            Push IDM_CLEAR
            Push WM_COMMAND
                Push hWnd
                Call SendMessage

            .ENDIF

        .ENDIF

        .ENDIF

    .ELSE

        Push lParam
        Push wParam
        Push uMsg
        Push hWnd
        Call DefWindowProc

        Ret

    .ENDIF

    Xor Eax, Eax

    Ret

WndProc 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 combine this tutorial with a string comparison function and make an app where you can compare a hard coded string to a string input by the user, so until then, enjoy.


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