Assembly language examples using NASM on Windows
Basic Window - 64 bit
Description
Creates a basic window, 64 bit. This could be used as the starting point for a larger GUI application.
Assemble
- nasm -f win64 BasicWindow64.asm -o BasicWindow64.obj
Link
- golink /entry:Start kernel32.dll user32.dll BasicWindow64.obj
- polink /ENTRY:Start /SUBSYSTEM:WINDOWS /LIBPATH:c:\lib64 kernel32.lib user32.lib BasicWindow64.obj
Notes
Double click the icon to run the executable.
The window can only be moved, resized and closed.
The window is not centred on the screen.
The window is the correct width and height, but we actually wanted the client area that size instead. This is due to the window frame
and menu bar not being taken in to consideration.
No attempt has been made to optimise how the shadow space is allocated and deallocated.
All RSP subtraction and addition is written out in full before and after each Windows API function call, this is to make it clear
as to what needs to be done.
An optimisation could be, only allocate at the start of each stack frame, with enough space for the function that takes the most
number of parameters, and keeping the stack 16 byte aligned.
Code
COLOR_WINDOW EQU 5
CS_BYTEALIGNWINDOW EQU 2000h
CS_HREDRAW EQU 2
CS_VREDRAW EQU 1
CW_USEDEFAULT EQU 80000000h
IDC_ARROW EQU 7F00h
IDI_APPLICATION EQU 7F00h
IMAGE_CURSOR EQU 2
IMAGE_ICON EQU 1
LR_SHARED EQU 8000h
NULL EQU 0
SW_SHOWNORMAL EQU 1
WM_DESTROY EQU 2
WS_EX_COMPOSITED EQU 2000000h
WS_OVERLAPPEDWINDOW EQU 0CF0000h
WindowWidth EQU 640
WindowHeight EQU 480
extern CreateWindowExA
extern DefWindowProcA
extern DispatchMessageA
extern ExitProcess
extern GetMessageA
extern GetModuleHandleA
extern IsDialogMessageA
extern LoadImageA
extern PostQuitMessage
extern RegisterClassExA
extern ShowWindow
extern TranslateMessage
extern UpdateWindow
global Start
section .data
WindowName db "Basic Window 64", 0
ClassName db "Window", 0
section .bss
alignb 8
hInstance resq 1
section .text
Start:
sub RSP, 8
sub RSP, 32
xor ECX, ECX
call GetModuleHandleA
mov qword [REL hInstance], RAX
add RSP, 32
call WinMain
.Exit:
xor ECX, ECX
call ExitProcess
WinMain:
push RBP
mov RBP, RSP
sub RSP, 136 + 8
%define wc RBP - 136
%define wc.cbSize RBP - 136
%define wc.style RBP - 132
%define wc.lpfnWndProc RBP - 128
%define wc.cbClsExtra RBP - 120
%define wc.cbWndExtra RBP - 116
%define wc.hInstance RBP - 112
%define wc.hIcon RBP - 104
%define wc.hCursor RBP - 96
%define wc.hbrBackground RBP - 88
%define wc.lpszMenuName RBP - 80
%define wc.lpszClassName RBP - 72
%define wc.hIconSm RBP - 64
%define msg RBP - 56
%define msg.hwnd RBP - 56
%define msg.message RBP - 48
%define msg.Padding1 RBP - 44
%define msg.wParam RBP - 40
%define msg.lParam RBP - 32
%define msg.time RBP - 24
%define msg.py.x RBP - 20
%define msg.pt.y RBP - 16
%define msg.Padding2 RBP - 12
%define hWnd RBP - 8
mov dword [wc.cbSize], 80
mov dword [wc.style], CS_HREDRAW | CS_VREDRAW | CS_BYTEALIGNWINDOW
lea RAX, [REL WndProc]
mov qword [wc.lpfnWndProc], RAX
mov dword [wc.cbClsExtra], NULL
mov dword [wc.cbWndExtra], NULL
mov RAX, qword [REL hInstance]
mov qword [wc.hInstance], RAX
sub RSP, 32 + 16
xor ECX, ECX
mov EDX, IDI_APPLICATION
mov R8D, IMAGE_ICON
xor R9D, R9D
mov qword [RSP + 4 * 8], NULL
mov qword [RSP + 5 * 8], LR_SHARED
call LoadImageA
mov qword [wc.hIcon], RAX
add RSP, 48
sub RSP, 32 + 16
xor ECX, ECX
mov EDX, IDC_ARROW
mov R8D, IMAGE_CURSOR
xor R9D, R9D
mov qword [RSP + 4 * 8], NULL
mov qword [RSP + 5 * 8], LR_SHARED
call LoadImageA
mov qword [wc.hCursor], RAX
add RSP, 48
mov qword [wc.hbrBackground], COLOR_WINDOW + 1
mov qword [wc.lpszMenuName], NULL
lea RAX, [REL ClassName]
mov qword [wc.lpszClassName], RAX
sub RSP, 32 + 16
xor ECX, ECX
mov EDX, IDI_APPLICATION
mov R8D, IMAGE_ICON
xor R9D, R9D
mov qword [RSP + 4 * 8], NULL
mov qword [RSP + 5 * 8], LR_SHARED
call LoadImageA
mov qword [wc.hIconSm], RAX
add RSP, 48
sub RSP, 32
lea RCX, [wc]
call RegisterClassExA
add RSP, 32
sub RSP, 32 + 64
mov ECX, WS_EX_COMPOSITED
lea RDX, [REL ClassName]
lea R8, [REL WindowName]
mov R9D, WS_OVERLAPPEDWINDOW
mov dword [RSP + 4 * 8], CW_USEDEFAULT
mov dword [RSP + 5 * 8], CW_USEDEFAULT
mov dword [RSP + 6 * 8], WindowWidth
mov dword [RSP + 7 * 8], WindowHeight
mov qword [RSP + 8 * 8], NULL
mov qword [RSP + 9 * 8], NULL
mov RAX, qword [REL hInstance]
mov qword [RSP + 10 * 8], RAX
mov qword [RSP + 11 * 8], NULL
call CreateWindowExA
mov qword [hWnd], RAX
add RSP, 96
sub RSP, 32
mov RCX, qword [hWnd]
mov EDX, SW_SHOWNORMAL
call ShowWindow
add RSP, 32
sub RSP, 32
mov RCX, qword [hWnd]
call UpdateWindow
add RSP, 32
.MessageLoop:
sub RSP, 32
lea RCX, [msg]
xor EDX, EDX
xor R8D, R8D
xor R9D, R9D
call GetMessageA
add RSP, 32
cmp RAX, 0
je .Done
sub RSP, 32
mov RCX, qword [hWnd]
lea RDX, [msg]
call IsDialogMessageA
add RSP, 32
cmp RAX, 0
jne .MessageLoop
sub RSP, 32
lea RCX, [msg]
call TranslateMessage
add RSP, 32
sub RSP, 32
lea RCX, [msg]
call DispatchMessageA
add RSP, 32
jmp .MessageLoop
.Done:
mov RSP, RBP
pop RBP
xor EAX, EAX
ret
WndProc:
push RBP
mov RBP, RSP
%define hWnd RBP + 16
%define uMsg RBP + 24
%define wParam RBP + 32
%define lParam RBP + 40
mov qword [hWnd], RCX
mov qword [uMsg], RDX
mov qword [wParam], R8
mov qword [lParam], R9
cmp qword [uMsg], WM_DESTROY
je WMDESTROY
DefaultMessage:
sub RSP, 32
mov RCX, qword [hWnd]
mov RDX, qword [uMsg]
mov R8, qword [wParam]
mov R9, qword [lParam]
call DefWindowProcA
add RSP, 32
mov RSP, RBP
pop RBP
ret
WMDESTROY:
sub RSP, 32
xor ECX, ECX
call PostQuitMessage
add RSP, 32
xor EAX, EAX
mov RSP, RBP
pop RBP
ret