[Download source code.]
.386
.model flat
; If using TLINK32, don't include vlib.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 'Window with menu',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
.code
extrn LoadMenuIndirect:near
push offset appMenuTemplate
call LoadMenuIndirect
mov [esp+36],eax ; set hMenu argument in stack
.code
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
;
; Menu item (command) IDs
;
IDM_EXIT equ 101
IDM_HELP equ 901
IDM_ABOUT equ 902
;
; Menu template
;
MFR_END equ 80h
MFR_POPUP equ 01h
.data
align 4 ; must align on DWORD boundary
appMenuTemplate dw 1 ; menu template version
dw 4 ; offset from end of this word to menu item list
dd 0 ; menu bar help ID
dd MFT_STRING,MFS_ENABLED,0
dw MFR_POPUP ; first column
dw '&','F','i','l','e',0,0 ; pad to align 4
dd 0 ; popup help ID
dd MFT_STRING,MFS_ENABLED,IDM_EXIT
dw MFR_END ; bottom of column
dw 'E','&','x','i','t',0,0 ; pad to align 4
dd MFT_STRING,MFS_ENABLED,0
dw MFR_POPUP or MFR_END ; second column, last one
dw '&','H','e','l','p',0,0 ; pad to align 4
dd 0 ; popup help ID
dd MFT_STRING,MFS_ENABLED,IDM_HELP
dw 0
dw '&','H','e','l','p','.','.','.',0
dd MFT_SEPARATOR,0,0
dw 0
dw 0 ; pad to align 4
dd MFT_STRING,MFS_ENABLED,IDM_ABOUT
dw MFR_END ; bottom of column
dw '&','A','b','o','u','t','.','.','.',0,0
.code
extrn DefWindowProc:near,PostQuitMessage:near
WndProc:
mov eax,[esp+4+4] ; message ID
cmp eax,WM_COMMAND ; from menu, accelerator, or control
je on_command
cmp eax,WM_DESTROY ; window will be destroyed
je on_destroy
jmp DefWindowProc ; delegate other message processing
on_destroy:
push large 0
call PostQuitMessage
xor eax,eax
ret 16
on_command:
mov eax,[esp+4+8] ; wParam
and eax,large 0FFFFh ; command ID
cmp eax,IDM_EXIT
je on_exit_command
cmp eax,IDM_HELP
je on_help_command
cmp eax,IDM_ABOUT
je on_about_command
xor eax,eax ; ignore other commands
ret 16
We use MessageBox to display messages when the non-exit menu items are selected.
.data
helpCaption equ wnd_title
helpText db 'Help not implemented.',0
aboutCaption db 'About Win32 Assembly',0
aboutText db 'Place your copyright here.',0
.code
extrn SendMessage:near
extrn MessageBox:near
on_exit_command:
; trigger the main window close function
mov eax,[esp+4+0] ; get hWnd before stack changes
push large 0 ; lParam
push large 0 ; wParam
push large WM_CLOSE ; msgid
push eax ; hwnd
call SendMessage
xor eax,eax
ret 16
on_help_command:
mov eax,[esp+4+0] ; get hWnd before stack changes
push large MB_OK
push offset helpCaption
push offset helpText
push eax ; owner window
call MessageBox
xor eax,eax
ret 16
on_about_command:
mov eax,[esp+4+0] ; get hWnd before stack changes
push large MB_OK
push offset aboutCaption
push offset aboutText
push eax ; owner window
call MessageBox
xor eax,eax
ret 16
end _start