;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