;Win03.ASM : An Internal MENU Structure. No External.RC File (May 10, 2024)
;===================================================================
;NOTES:
; The " %include " paths at the start of the file might need to be
; changed to suit your own disk directory setup.
; Command Lines:
; Assembly: nasm -f win32 Win03.asm -o Win03.obj
; GoLink.exe: golink.exe /entry:start Win03.obj kernel32.dll user32.dll
;
; Note there is NO .RES file on the golink.exe command line.
;
;===========================================================================
; This sample uses a simple menu defined in a memory template in the
; data section. Thus, there is no external .RC or .RES file. This is
; useful if the application needs to change the menu structure after
; launch.
; A downside is that the application code becomes larger.
;
; There's also a small nag with LoadMenuIndirect (LMI). Even though LMI
; appears to have an ANSI version (LoadMenuIndirectA) the strings used in
; the menu template must be in wide char. This requires byte to wide char
; conversion.
;===========================================================================
%include '\nasm32\inc\win32\windows.inc'
%include '\nasm32\inc\win32\kernel32.inc'
%include '\nasm32\inc\win32\user32.inc'
%include '\nasm32\inc\nasm32.inc'
; ---------------
[section .data]
; ---------------
;----------------
;STRUC Instances
;----------------
wcx times WNDCLASSEX_size db 0
msg times MSG_size db 0
;---------------
;HANDLES
;----------------
hInstance dd 0
hWnd dd 0
hMenu dd 0
;-----------------------
;WNDCLASSEX LABELS
;------------------------
szTitle db 'Win03 : NASM Window With Menu From Memory Template',0x0
szClass db 'Win03 Class',0x0
IDM_EXIT equ 102
;----------------------
;ANSI/ASCII MENU LABELS
;-----------------------
mLblClick db "Click Me",0
lmLblClick equ $-mLblClick ;len of mLblClick
mLblExit db "Exit Win03",0
lmLblExit equ $-mLblExit ;len of mLblExit
;testbyte db 0
align 2 ; Align MENUTEMPLATEHEADER on the next WORD. THIS IS IMPORTANT.
; To see why, change the ALIGN directive into a comment and
; UN_comment the variable "testbyte". Now, recompile, and
; watch what happens when you press "Click Me". Without the
; align directive the base address of Win03_Menu starts
; at whatever memory offset is the sum of all of the previous
; bytes in the file. If this isn't a WORD boundary the menu
; display becomes bogus. It's possible that the exact number of
; bytes preceding the label will work out to a WORD offset but using
; ALIGN guarantees it.
;------------------------------
;Define a MENUITEMTEMPLATEHEADER
;------------------------------
Win03_Menu dw 0
dw 0
;------------------------------
;Define a MENUITEMTEMPLATE
;------------------------------
dw MF_POPUP +MF_END ;Menu item flags. MF_END says this is the last item in
; this MENUITEMTEMPLATE
;No MenuItemID value here because flag is MF_POPUP - it's
; just another list of selections.
wLblClick times ((lmLblClick)*2) db 0 ;Buffer for wide char string("Click Me").
lwLblClick EQU $wLblClick ; Size of buffer.
;------------------------------
;Define another MENUITEMTEMPLATE
;------------------------------
dw MF_STRING +MF_END ;Menu item flag(s)
dw IDM_EXIT ;Menu item ID used here because this is a true
; menu item, not just another selection list.
wLblExit times ((lmLblExit)*2) db 0 ;Buffer for wide char string "Exit".
lwLblExit EQU $wLblExit ; Buffer size.
;=============================================================================
; ---------------
[section .text]
; ---------------
start: ;This label is for GoLink.exe
proc Win03
invoke GetModuleHandleA, dword NULL
mov [hInstance], eax
invoke WinMain,dword [hInstance],dword NULL,dword NULL,dword SW_SHOWNORMAL
invoke ExitProcess,dword NULL
ret
endproc ;Win03
;--------------------------- WINMAIN -----------------------------------
proc WinMain ,hInst,hPinst,CmdLn,dwShow
;--------------------------------------------
;Convert Menu String "Click Me" To Wide Char
;--------------------------------------------
;Convert "Click Me" to wide char
invoke MultiByteToWideChar ,CP_ACP, MB_PRECOMPOSED,\
mLblClick,-1,wLblClick,lwLblClick
;Convert "Exit" to wide char
invoke MultiByteToWideChar ,CP_ACP ,MB_PRECOMPOSED, \
mLblExit,-1,wLblExit ,lwLblExit
;-----------
;Load Menu
;-----------
invoke LoadMenuIndirectA, Win03_Menu
mov dword [hMenu],eax
;Memory block reserved for wcx [WNDCLASSEX] has no data yet.
push dword WNDCLASSEX_size
pop dword [wcx + WNDCLASSEX.cbSize]
push dword argv(hInst)
pop dword [wcx + WNDCLASSEX.hInstance]
push dword szClass
pop dword [wcx + WNDCLASSEX.lpszClassName]
push dword WndProc ; Adr of WndProc
pop dword [wcx + WNDCLASSEX.lpfnWndProc]
push dword COLOR_BTNFACE +1
pop dword [wcx + WNDCLASSEX.hbrBackground]
push dword CS_VREDRAW +CS_HREDRAW
pop dword [wcx + WNDCLASSEX.style]
push dword Win03_Menu ;szMenuName
pop dword [wcx + WNDCLASSEX.lpszMenuName]
invoke RegisterClassExA, dword wcx
;--------------------
;Create the window
;--------------------
invoke CreateWindowExA,\
WS_EX_OVERLAPPEDWINDOW,\
szClass,\
szTitle,\
WS_OVERLAPPEDWINDOW +WS_VISIBLE ,\
100, 120, 600, 232,\
NULL,\
dword [hMenu],\
[wcx + WNDCLASSEX.hInstance],\
NULL
mov [hWnd], eax
;-------------------------
;Process Windows Messages
;-------------------------
MsgGet:
invoke GetMessageA, dword msg, dword NULL, dword NULL, dword NULL
cmp eax,0
jnz MsgProcess
jmp MsgEnd
MsgProcess:
invoke TranslateMessage, dword msg
invoke DispatchMessageA, dword msg
jmp MsgGet
MsgEnd:
ret
endproc ;WinMain
;--------------------------------------------------------------------
; Windows Callback
;-----------------------------------------------------------------------
proc WndProc, hWin, uMsg, wParam, lParam
Is_WM_KEYDOWN?:
cmp dword argv(uMsg),dword WM_KEYDOWN
jnz Is_Command?
;WM_COMMAND msg
cmp argv(wParam), dword VK_ESCAPE ; ESC Key ?
jz ExitApp ;ESC struck. Quit application.
xor eax,eax ;WM_KEYDOWN msg handled, but not what we want. xor eax and ret.
ret
;-------------------------------------------
Is_Command?:
cmp dword argv(uMsg),WM_COMMAND
jnz Is_Destroy?
;WM_COMMAND msg
cmp dword argv(wParam),IDM_EXIT; Menu command # 102 (EXIT)?
jz ExitApp ;Menu Exit hit.
xor eax,eax
ret
;-------------------------------------------
Is_Destroy?:
cmp dword argv(uMsg),dword WM_DESTROY
jnz DefWndProc
jmp ExitApp
DefWndProc:
invoke DefWindowProcA, dword argv(hWin), dword argv(uMsg), dword argv(wParam), dword argv(lParam)
ret
ExitApp:
invoke PostQuitMessage, dword NULL
ret
endproc ;WndProc
;==============================================
;mcamember May 9, 2024