Our basic GUI program handles the reception of messages in two parts: the first part inspects the message queue and the second part actually decides how to respond to a given message. Our basic GUI program is written primarily as a receiver or consumer of messages. The senders or producers of these messages are either the Windows API functions or the Windows system itself.
.386
.model flat
; If using TLINK32
don't include vclib.inc
include vclib.inc ; Microsoft VC++ .lib link names
include win32hst.inc ; constants
structures
and entry names
.data
align 4
wcx dd size WNDCLASSEX ; cbSize
dd CS_VREDRAW or CS_HREDRAW ; style
dd WndProc ; lpfnWndProc
dd 0
0 ; cbClsExtra
cbWndExtra
dd 0 ; hInstance
dd 0 ; hIcon
dd 0 ; hCursor
dd COLOR_WINDOW+1 ; hbrBackground
dd 0 ; lpszMenuName
dd wndclsname ; lpszClassName
dd 0 ; hIconSm
wndclsname db 'winmain'
0
.code
public _start
extrn GetModuleHandle:near
extrn LoadIcon:near
LoadCursor:near
extrn RegisterClassEx:near
_start:
push large 0 ; NULL string pointer means
call GetModuleHandle ; get HINSTANCE/HMODULE of EXE file
mov [wcx.wcx_hInstance]
eax
push large IDI_WINLOGO
push large 0 ; hInstance
0 = stock icon
call LoadIcon
mov [wcx.wcx_hIcon]
eax
push large IDC_ARROW
push large 0 ; hInstance
0 = stock cursor
call LoadCursor
mov [wcx.wcx_hCursor]
eax
push offset wcx
call RegisterClassEx
.data
align 4
cwargs dd 0 ; dwExStyle
dd wndclsname ; lpszClass
dd wnd_title ; lpszName
dd WS_VISIBLE or WS_OVERLAPPED or WS_SYSMENU or WS_THICKFRAME \
or WS_MINIMIZEBOX or WS_MAXIMIZEBOX ; style
dd 100 ; x
dd 100 ; y
dd 400 ; cx (width)
dd 200 ; cy (height)
dd 0 ; hwndParent
dd 0 ; hMenu
dd 0 ; hInstance
dd 0 ; lpCreateParams
msgbuf MSG <>
wnd_title db 'Mouse activity'
0
.code
extrn CreateWindowEx:near
extrn GetMessage:near
DispatchMessage:near
extrn ExitProcess:near
sub esp
48 ; allocate argument list
mov esi
offset cwargs ; set block move source
mov edi
esp ; set block move destination
mov ecx
12 ; number of arguments
rep movsd
mov eax
[wcx.wcx_hInstance]
mov [esp+40]
eax ; set hInstance argument in stack
call CreateWindowEx
msg_loop:
push large 0 ; uMsgFilterMax
push large 0 ; uMsgFilterMin
push large 0 ; hWnd (filter)
0 = all windows
push offset msgbuf ; lpMsg
call GetMessage ; returns FALSE if WM_QUIT
or eax
eax
jz end_loop
push offset msgbuf
call DispatchMessage
jmp msg_loop
end_loop:
push large 0 ; (error) return code
call ExitProcess
.code extrn DefWindowProc:near PostQuitMessage:near WndProc: mov eax [esp+4+4] ; message ID cmp eax WM_DESTROY ; about to start window destruction je on_destroy cmp eax WM_LBUTTONDOWN ; left mouse button pressed je on_left_mouse_down cmp eax WM_LBUTTONUP ; left mouse button released je on_left_mouse_up cmp eax WM_RBUTTONDOWN ; right mouse button pressed je on_right_mouse_down cmp eax WM_RBUTTONUP ; right mouse button released je on_right_mouse_up cmp eax WM_MOUSEMOVE ; mouse moved je on_mouse_move jmp DefWindowProc ; delegate other message processing on_destroy: push large 0 call PostQuitMessage xor eax eax ret 16
.data
align 4
text_ldown db 'Left mouse button down'
0
text_lup db 'Left mouse button up'
0
text_rdown db 'Right mouse button down'
0
text_rup db 'Right mouse button up'
0
text_mmove db 'Mouse moved'
0
.code
extrn SetWindowText:near
on_left_mouse_down:
mov eax
[esp+4+0] ; get hwnd before changing ESP
push offset text_ldown
push eax
call SetWindowText
xor eax
eax
ret 16
on_left_mouse_up:
mov eax
[esp+4+0] ; get hwnd before changing ESP
push offset text_lup
push eax
call SetWindowText
xor eax
eax
ret 16
on_right_mouse_down:
mov eax
[esp+4+0] ; get hwnd before changing ESP
push offset text_rdown
push eax
call SetWindowText
xor eax
eax
ret 16
on_right_mouse_up:
mov eax
[esp+4+0] ; get hwnd before changing ESP
push offset text_rup
push eax
call SetWindowText
xor eax
eax
ret 16
on_mouse_move:
mov eax
[esp+4+0] ; get hwnd before changing ESP
push offset text_mmove
push eax
call SetWindowText
xor eax
eax
ret 16
end _start