Assembly language examples using NASM on Windows
Basic Window Extended - 32 bit
Description
Creates a window with simple functionality, 32 bit.
It demonstrates the processing of several WM_ messages, and improves upon the basic window example.
Assemble
- nasm -f win32 BasicWindowExtended32.asm -o BasicWindowExtended32.obj
Link
- golink /entry:Start kernel32.dll user32.dll gdi32.dll BasicWindowExtended32.obj
- polink /ENTRY:Start /SUBSYSTEM:WINDOWS /LIBPATH:c:\lib32 kernel32.lib user32.lib gdi32.lib BasicWindowExtended32.obj
Notes
Double click the icon to run the executable.
Improvements over the basic window example
- The window will be centred on the screen
- The client area will now be the correct size (before resizing)
- The window has a background colour
- 2 static controls are created. The text changes colour when clicked
- 2 edit controls are created. The tab key can be used to change focus
- The static and edit controls have their font changed from the system default
- A black rectangle is blitted to the window
- An exit confirmation is displayed when closing the window
Optimisations
When a WM_ message has been processed, Windows usually expects a return value of 0. There now is a single point of return where
EAX is zeroed and the stack frame removed.
WM_CTLCOLOREDIT and WM_CTLCOLORSTATIC need a brush returned instead, in these cases the zeroing of EAX is skipped over.
Code
ANSI_CHARSET EQU 0
BLACKNESS EQU 42h
CLIP_DEFAULT_PRECIS EQU 0
CS_BYTEALIGNWINDOW EQU 2000h
CS_HREDRAW EQU 2
CS_VREDRAW EQU 1
DEFAULT_PITCH EQU 0
ES_AUTOHSCROLL EQU 80h
ES_CENTER EQU 1
FALSE EQU 0
GRAY_BRUSH EQU 2
IDC_ARROW EQU 7F00h
IDI_APPLICATION EQU 7F00h
IDNO EQU 7
IMAGE_CURSOR EQU 2
IMAGE_ICON EQU 1
LR_SHARED EQU 8000h
MB_DEFBUTTON2 EQU 100h
MB_YESNO EQU 4
NULL EQU 0
NULL_BRUSH EQU 5
OPAQUE EQU 2
PROOF_QUALITY EQU 2
SM_CXFULLSCREEN EQU 10h
SM_CYFULLSCREEN EQU 11h
SS_CENTER EQU 1
SS_NOTIFY EQU 100h
SW_SHOWNORMAL EQU 1
TRUE EQU 1
WM_CLOSE EQU 10h
WM_COMMAND EQU 111h
WM_CREATE EQU 1
WM_CTLCOLOREDIT EQU 133h
WM_CTLCOLORSTATIC EQU 138h
WM_DESTROY EQU 2
WM_PAINT EQU 0Fh
WM_SETFONT EQU 30h
OUT_DEFAULT_PRECIS EQU 0
WS_CHILD EQU 40000000h
WS_EX_COMPOSITED EQU 2000000h
WS_OVERLAPPEDWINDOW EQU 0CF0000h
WS_TABSTOP EQU 10000h
WS_VISIBLE EQU 10000000h
WindowWidth EQU 640
WindowHeight EQU 170
Static1ID EQU 100
Static2ID EQU 101
Edit1ID EQU 102
Edit2ID EQU 103
extern _AdjustWindowRectEx@16
extern _BeginPaint@8
extern _BitBlt@36
extern _CreateFontA@56
extern _CreateSolidBrush@4
extern _CreateWindowExA@48
extern _DefWindowProcA@16
extern _DeleteObject@4
extern _DestroyWindow@4
extern _DispatchMessageA@4
extern _EndPaint@8
extern _ExitProcess@4
extern _GetDlgCtrlID@4
extern _GetMessageA@16
extern _GetModuleHandleA@4
extern _GetStockObject@4
extern _GetSystemMetrics@4
extern _InvalidateRect@12
extern _IsDialogMessageA@8
extern _LoadImageA@24
extern _MessageBoxA@16
extern _PostQuitMessage@4
extern _RegisterClassExA@4
extern _SendMessageA@16
extern _SetBkColor@8
extern _SetBkMode@8
extern _SetTextColor@8
extern _ShowWindow@8
extern _TranslateMessage@4
extern _UpdateWindow@4
global Start
section .data
Static1Colour dd 0F0F0F0h
Static1ColourA dd 020A0F0h
Static2Colour dd 000FFFFh
Static2ColourA dd 08000FFh
Edit1TextColour dd 0F590F5h
Edit1BackColour dd 0A00000h
Edit2TextColour dd 0A56E3Bh
Edit2BackColour dd 0FEFE8Eh
BackgroundColour dd 0A56E3Bh
WindowName db "Basic Window Extended 32", 0
ClassName db "Window", 0
SegoeUI db "Segoe UI", 0
StaticClass db "STATIC", 0
EditClass db "EDIT", 0
Text1 db "ABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789", 0
Text2 db "abcdefghijklmnopqrstuvwxyz_0123456789", 0
ExitText db "Do you want to exit?", 0
section .bss
hInstance resd 1
BackgroundBrush resd 1
Font resd 1
Static1 resd 1
Static2 resd 1
Edit1 resd 1
Edit2 resd 1
section .text
Start:
push NULL
call _GetModuleHandleA@4
mov dword [hInstance], EAX
call WinMain
.Exit:
push NULL
call _ExitProcess@4
WinMain:
push EBP
mov EBP, ESP
sub ESP, 104
%define Screen.Width EBP - 104
%define Screen.Height EBP - 100
%define ClientArea EBP - 96
%define ClientArea.left EBP - 96
%define ClientArea.top EBP - 92
%define ClientArea.right EBP - 88
%define ClientArea.bottom EBP - 84
%define wc EBP - 80
%define wc.cbSize EBP - 80
%define wc.style EBP - 76
%define wc.lpfnWndProc EBP - 72
%define wc.cbClsExtra EBP - 68
%define wc.cbWndExtra EBP - 64
%define wc.hInstance EBP - 60
%define wc.hIcon EBP - 56
%define wc.hCursor EBP - 52
%define wc.hbrBackground EBP - 48
%define wc.lpszMenuName EBP - 44
%define wc.lpszClassName EBP - 40
%define wc.hIconSm EBP - 36
%define msg EBP - 32
%define msg.hwnd EBP - 32
%define msg.message EBP - 28
%define msg.wParam EBP - 24
%define msg.lParam EBP - 20
%define msg.time EBP - 16
%define msg.pt.x EBP - 12
%define msg.pt.y EBP - 8
%define hWnd EBP - 4
push dword [BackgroundColour]
call _CreateSolidBrush@4
mov dword [BackgroundBrush], EAX
mov dword [wc.cbSize], 48
mov dword [wc.style], CS_HREDRAW | CS_VREDRAW | CS_BYTEALIGNWINDOW
mov dword [wc.lpfnWndProc], WndProc
mov dword [wc.cbClsExtra], NULL
mov dword [wc.cbWndExtra], NULL
mov EAX, dword [hInstance]
mov dword [wc.hInstance], EAX
push LR_SHARED
push NULL
push NULL
push IMAGE_ICON
push IDI_APPLICATION
push NULL
call _LoadImageA@24
mov dword [wc.hIcon], EAX
push LR_SHARED
push NULL
push NULL
push IMAGE_CURSOR
push IDC_ARROW
push NULL
call _LoadImageA@24
mov dword [wc.hCursor], EAX
mov EAX, dword [BackgroundBrush]
mov dword [wc.hbrBackground], EAX
mov dword [wc.lpszMenuName], NULL
mov dword [wc.lpszClassName], ClassName
push LR_SHARED
push NULL
push NULL
push IMAGE_ICON
push IDI_APPLICATION
push NULL
call _LoadImageA@24
mov dword [wc.hIconSm], EAX
lea EAX, [wc]
push EAX
call _RegisterClassExA@4
push SM_CXFULLSCREEN
call _GetSystemMetrics@4
mov dword [Screen.Width], EAX
push SM_CYFULLSCREEN
call _GetSystemMetrics@4
mov dword [Screen.Height], EAX
mov dword [ClientArea.left], 0
mov dword [ClientArea.top], 0
mov dword [ClientArea.right], WindowWidth
mov dword [ClientArea.bottom], WindowHeight
push WS_EX_COMPOSITED
push NULL
push WS_OVERLAPPEDWINDOW
lea EAX, [ClientArea]
push EAX
call _AdjustWindowRectEx@16
mov EAX, dword [ClientArea.top]
sub dword [ClientArea.bottom], EAX
mov EAX, dword [ClientArea.left]
sub dword [ClientArea.right], EAX
push NULL
push dword [hInstance]
push NULL
push NULL
push dword [ClientArea.bottom]
push dword [ClientArea.right]
xor ECX, ECX
mov EAX, dword [Screen.Height]
sub EAX, dword [ClientArea.bottom]
cmovs EAX, ECX
shr EAX, 1
push EAX
mov EAX, dword [Screen.Width]
sub EAX, dword [ClientArea.right]
cmovs EAX, ECX
shr EAX, 1
push EAX
push WS_OVERLAPPEDWINDOW
push WindowName
push ClassName
push WS_EX_COMPOSITED
call _CreateWindowExA@48
mov dword [hWnd], EAX
push SW_SHOWNORMAL
push dword [hWnd]
call _ShowWindow@8
push dword [hWnd]
call _UpdateWindow@4
.MessageLoop:
push NULL
push NULL
push NULL
lea EAX, [msg]
push EAX
call _GetMessageA@16
cmp EAX, 0
je .Done
lea EAX, [msg]
push EAX
push dword [hWnd]
call _IsDialogMessageA@8
cmp EAX, 0
jne .MessageLoop
lea EAX, [msg]
push EAX
call _TranslateMessage@4
lea EAX, [msg]
push EAX
call _DispatchMessageA@4
jmp .MessageLoop
.Done:
xor EAX, EAX
mov ESP, EBP
pop EBP
ret
WndProc:
push EBP
mov EBP, ESP
sub ESP, 68
%define hWnd EBP + 8
%define uMsg EBP + 12
%define wParam EBP + 16
%define lParam EBP + 20
%define ps EBP - 68
%define ps.hdc EBP - 68
%define ps.fErase EBP - 64
%define ps.rcPaint.left EBP - 60
%define ps.rcPaint.top EBP - 56
%define ps.rcPaint.right EBP - 52
%define ps.rcPaint.bottom EBP - 48
%define ps.Restore EBP - 44
%define ps.fIncUpdate EBP - 40
%define ps.rgbReserved EBP - 36
%define hdc EBP - 4
cmp dword [uMsg], WM_CLOSE
je WMCLOSE
cmp dword [uMsg], WM_COMMAND
je WMCOMMAND
cmp dword [uMsg], WM_CREATE
je WMCREATE
cmp dword [uMsg], WM_CTLCOLOREDIT
je WMCTLCOLOREDIT
cmp dword [uMsg], WM_CTLCOLORSTATIC
je WMCTLCOLORSTATIC
cmp dword [uMsg], WM_DESTROY
je WMDESTROY
cmp dword [uMsg], WM_PAINT
je WMPAINT
DefaultMessage:
push dword [lParam]
push dword [wParam]
push dword [uMsg]
push dword [hWnd]
call _DefWindowProcA@16
jmp Return
WMCLOSE:
push MB_YESNO | MB_DEFBUTTON2
push WindowName
push ExitText
push dword [hWnd]
call _MessageBoxA@16
cmp EAX, IDNO
je Return.WM_Processed
push dword [hWnd]
call _DestroyWindow@4
jmp Return.WM_Processed
WMCOMMAND:
mov EAX, dword [wParam]
cmp AX, Static1ID
je .Static1
cmp AX, Static2ID
je .Static2
jmp Return.WM_Processed
.Static1:
mov EAX, dword [Static1Colour]
mov EBX, dword [Static1ColourA]
mov dword [Static1Colour], EBX
mov dword [Static1ColourA], EAX
push TRUE
push NULL
push dword [lParam]
call _InvalidateRect@12
jmp Return.WM_Processed
.Static2:
mov EAX, dword [Static2Colour]
mov EBX, dword [Static2ColourA]
mov dword [Static2Colour], EBX
mov dword [Static2ColourA], EAX
push TRUE
push NULL
push dword [lParam]
call _InvalidateRect@12
jmp Return.WM_Processed
WMCREATE:
push NULL
push dword [hInstance]
push Static1ID
push dword [hWnd]
push 20
push 400
push 10
push 120
push WS_CHILD | WS_VISIBLE | SS_NOTIFY | SS_CENTER
push Text1
push StaticClass
push NULL
call _CreateWindowExA@48
mov dword [Static1], EAX
push NULL
push dword [hInstance]
push Static2ID
push dword [hWnd]
push 20
push 400
push 40
push 120
push WS_CHILD | WS_VISIBLE | SS_NOTIFY | SS_CENTER
push Text2
push StaticClass
push NULL
call _CreateWindowExA@48
mov dword [Static2], EAX
push NULL
push dword [hInstance]
push Edit1ID
push dword [hWnd]
push 20
push 400
push 70
push 120
push WS_CHILD | WS_VISIBLE | ES_CENTER | WS_TABSTOP | ES_AUTOHSCROLL
push Text1
push EditClass
push NULL
call _CreateWindowExA@48
mov dword [Edit1], EAX
push NULL
push dword [hInstance]
push Edit2ID
push dword [hWnd]
push 20
push 400
push 100
push 120
push WS_CHILD | WS_VISIBLE | ES_CENTER | WS_TABSTOP | ES_AUTOHSCROLL
push Text2
push EditClass
push NULL
call _CreateWindowExA@48
mov dword [Edit2], EAX
lea EAX, [SegoeUI]
push EAX
push DEFAULT_PITCH
push PROOF_QUALITY
push CLIP_DEFAULT_PRECIS
push OUT_DEFAULT_PRECIS
push ANSI_CHARSET
push NULL
push NULL
push NULL
push 400
push NULL
push NULL
push NULL
push 20
call _CreateFontA@56
mov dword [Font], EAX
push FALSE
push dword [Font]
push WM_SETFONT
push dword [Static1]
call _SendMessageA@16
push FALSE
push dword [Font]
push WM_SETFONT
push dword [Static2]
call _SendMessageA@16
push FALSE
push dword [Font]
push WM_SETFONT
push dword [Edit1]
call _SendMessageA@16
push FALSE
push dword [Font]
push WM_SETFONT
push dword [Edit2]
call _SendMessageA@16
jmp Return.WM_Processed
WMCTLCOLOREDIT:
push dword [lParam]
call _GetDlgCtrlID@4
cmp EAX, Edit1ID
je .Edit1
cmp EAX, Edit2ID
je .Edit2
.Default:
push NULL_BRUSH
call _GetStockObject@4
jmp Return
.Edit1:
push dword [Edit1TextColour]
push dword [wParam]
call _SetTextColor@8
push OPAQUE
push dword [wParam]
call _SetBkMode@8
push dword [Edit1BackColour]
push dword [wParam]
call _SetBkColor@8
push NULL_BRUSH
call _GetStockObject@4
jmp Return
.Edit2:
push dword [Edit2TextColour]
push dword [wParam]
call _SetTextColor@8
push OPAQUE
push dword [wParam]
call _SetBkMode@8
push dword [Edit2BackColour]
push dword [wParam]
call _SetBkColor@8
push NULL_BRUSH
call _GetStockObject@4
jmp Return
WMCTLCOLORSTATIC:
push dword [lParam]
call _GetDlgCtrlID@4
cmp EAX, Static1ID
je .Static1
cmp EAX, Static2ID
je .Static2
.Default:
push NULL_BRUSH
call _GetStockObject@4
jmp Return
.Static1:
push dword [Static1Colour]
push dword [wParam]
call _SetTextColor@8
push OPAQUE
push dword [wParam]
call _SetBkMode@8
push 0604060h
push dword [wParam]
call _SetBkColor@8
push NULL_BRUSH
call _GetStockObject@4
jmp Return
.Static2:
push dword [Static2Colour]
push dword [wParam]
call _SetTextColor@8
push OPAQUE
push dword [wParam]
call _SetBkMode@8
push 0005000h
push dword [wParam]
call _SetBkColor@8
push GRAY_BRUSH
call _GetStockObject@4
jmp Return
WMDESTROY:
push dword [BackgroundBrush]
call _DeleteObject@4
push dword [Font]
call _DeleteObject@4
push NULL
call _PostQuitMessage@4
jmp Return.WM_Processed
WMPAINT:
lea EAX, [ps]
push EAX
push dword [hWnd]
call _BeginPaint@8
mov dword [hdc], EAX
push BLACKNESS
push 0
push 0
push dword [hdc]
push 20
push 400
push 130
push 120
push dword [hdc]
call _BitBlt@36
lea EAX, [ps]
push EAX
push dword [hWnd]
call _EndPaint@8
Return.WM_Processed:
xor EAX, EAX
Return:
mov ESP, EBP
pop EBP
ret 16