[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