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