Hi,
I'm trying to make an app with menu and events service. I made RC file based on win32 sample but it doesn't work fully with my source. RC compiles and is linked to OBJ but window appears without menu. Below are sources:
;--------MAKE-------------------------------------------------------------
;rc menu_app.rc
;
;jwasm -win64 menu_app.asm
;
;link /SUBSYSTEM:WINDOWS menu_app.obj menu_app.res
;
;--------INCLUDES---------------------------------------------------------
includelib /JWASM/wininc208/lib64/kernel32.lib
includelib /JWASM/wininc208/lib64/user32.lib
includelib /JWASM/wininc208/lib64/gdi32.lib
option casemap:none
;--------PROTOS-----------------------------------------------------------
HINSTANCE typedef QWORD
HWND typedef QWORD
HMENU typedef QWORD
HICON typedef QWORD
HBRUSH typedef QWORD
HCURSOR typedef QWORD
WPARAM typedef QWORD
LPARAM typedef QWORD
LPSTR typedef QWORD
LPVOID typedef QWORD
UINT typedef DWORD
NULL equ 0
WS_OVERLAPPEDWINDOW equ 0CF0000h
CW_USEDEFAULT equ 80000000h
SW_SHOWDEFAULT equ 10
SW_SHOWNORMAL equ 1
IDC_ARROW equ 32512
IDI_APPLICATION equ 32512
WM_DESTROY equ 2
CS_VREDRAW equ 1
CS_HREDRAW equ 2
COLOR_WINDOW equ 5
WM_COMMAND equ 111h
IDM_TEST EQU 1
IDM_HELLO EQU 2
IDM_GOODBYE EQU 3
IDM_EXIT EQU 4
proto_WNDPROC typedef proto :HWND,:UINT,:WPARAM,:LPARAM
WNDPROC typedef ptr proto_WNDPROC
WNDCLASSEXA struct 8
cbSize DWORD ?
style DWORD ?
lpfnWndProc WNDPROC ?
cbClsExtra DWORD ?
cbWndExtra DWORD ?
hInstance HINSTANCE ?
hIcon HICON ?
hCursor HCURSOR ?
hbrBackground HBRUSH ?
lpszMenuName LPSTR ?
lpszClassName LPSTR ?
hIconSm HICON ?
WNDCLASSEXA ends
POINT struct
x SDWORD ?
y SDWORD ?
POINT ends
MSG struct 8
hwnd HWND ?
message DWORD ?
wParam WPARAM ?
lParam LPARAM ?
time DWORD ?
pt POINT <>
MSG ends
GetModuleHandleA proto :LPSTR
GetCommandLineA proto
ExitProcess proto :UINT
LoadIconA proto :HINSTANCE, :LPSTR
LoadCursorA proto :HINSTANCE, :LPSTR
RegisterClassExA proto :ptr WNDCLASSEXA
CreateWindowExA proto :DWORD, :LPSTR, :LPSTR, :DWORD, :SDWORD, :SDWORD, :SDWORD, :SDWORD, :HWND, :HMENU, :HINSTANCE, :LPVOID
ShowWindow proto :HWND, :SDWORD
UpdateWindow proto :HWND
GetMessageA proto :ptr MSG, :HWND, :SDWORD, :SDWORD
TranslateMessage proto :ptr MSG
DispatchMessageA proto :ptr MSG
PostQuitMessage proto :SDWORD
DefWindowProcA proto :HWND, :UINT, :WPARAM, :LPARAM
EXTERN LoadMenuA :PROC
EXTERN MessageBoxA :PROC
;WinMain proto :HINSTANCE, :HINSTANCE, :LPSTR, :UINT
.data
ClassName db "SimpleWinClass",0
AppName db "Our First Window",0
MenuName db "FirstMenu",0
Text db "Message test",0
Testing db "test",0
Hello db "Hello!",0
MenuFailed db "LOAD MENU FAILED!",0
.data?
hInstance HINSTANCE ?
CommandLine LPSTR ?
hMenu dq ?
.code
WinMainCRTStartup proc FRAME
push rbp
.pushreg rbp
mov rbp,rsp
.setframe rbp, 0
.endprolog
sub rsp,32
mov ecx,NULL
call GetModuleHandleA
mov hInstance, rax
call GetCommandLineA
mov CommandLine, rax
mov rcx, hInstance
mov rdx, NULL
mov r8, CommandLine
mov r9d, SW_SHOWDEFAULT
call WinMain
mov ecx, eax
call ExitProcess
align 4
WinMainCRTStartup endp
WinMain proc FRAME
push rbp
.pushreg rbp
mov rbp,rsp
.setframe rbp, 0
sub rsp, sizeof WNDCLASSEXA + sizeof MSG + sizeof HWND + 13*8 ;make sure rsp is 16-byte aligned
.allocstack sizeof WNDCLASSEXA + sizeof MSG + sizeof HWND + 13*8
.endprolog
hInst equ <[rbp+10h]>
hPrevInst equ <[rbp+18h]>
CmdLine equ <[rbp+20h]>
CmdShow equ <[rbp+28h]>
wc equ <[rbp - sizeof WNDCLASSEXA].WNDCLASSEXA>
msg equ <[rbp - sizeof WNDCLASSEXA - sizeof MSG].MSG>
hwnd equ <[rbp - sizeof WNDCLASSEXA - sizeof MSG - sizeof HWND]>
mov hInst, rcx ;store param1 in shadow space
mov wc.cbSize, SIZEOF WNDCLASSEXA
mov wc.style, CS_HREDRAW or CS_VREDRAW
;mov rax, OFFSET WndProc ;using LEA is preferable
lea rax, [WndProc]
mov wc.lpfnWndProc, rax
mov wc.cbClsExtra, 0
mov wc.cbWndExtra, 0
mov wc.hInstance, rcx
mov wc.hbrBackground, COLOR_WINDOW+1
mov wc.lpszMenuName, NULL
;mov rax, OFFSET ClassName ;using LEA is preferable
lea rax, [ClassName]
mov wc.lpszClassName, rax
mov ecx, NULL
mov edx, IDI_APPLICATION
call LoadIconA
mov wc.hIcon, rax
mov wc.hIconSm, rax
mov ecx, NULL
mov edx, IDC_ARROW
call LoadCursorA
mov wc.hCursor,rax
lea rcx, wc
call RegisterClassExA
lea rdx, [MenuName]
mov rcx, hInst
call LoadMenuA
mov hMenu, rax
mov ecx, NULL
lea rdx, [ClassName]
lea r8, [AppName]
mov r9d, WS_OVERLAPPEDWINDOW
mov dword ptr [rsp+4*8], CW_USEDEFAULT
mov dword ptr [rsp+5*8], CW_USEDEFAULT
mov dword ptr [rsp+6*8], CW_USEDEFAULT
mov dword ptr [rsp+7*8], CW_USEDEFAULT
mov qword ptr [rsp+8*8], NULL
mov qword ptr [rsp+9*8], NULL
mov rax, hInst
mov [rsp+10*8], rax
mov qword ptr [rsp+11*8], NULL
call CreateWindowExA
mov hwnd,rax
mov rcx, hwnd
mov edx, SW_SHOWNORMAL
call ShowWindow
mov rcx, hwnd
call UpdateWindow
;--- message loop
@@:
lea rcx, msg
mov rdx, NULL
mov r8, 0
mov r9, 0
call GetMessageA
and rax, rax
jz @F
lea rcx, msg
call TranslateMessage
lea rcx, msg
call DispatchMessageA
jmp @B
@@:
mov rax, msg.wParam
add rsp, sizeof WNDCLASSEXA + sizeof MSG + sizeof HWND + 13*8
pop rbp
ret
align 4
WinMain endp
WndProc proc FRAME
sub rsp, 5*8
.allocstack 5*8
.endprolog
hWnd equ <[rbp+10h]>
uMsg equ <[rbp+18h]>
wParam equ <[rbp+20h]>
lParam equ <[rbp+28h]>
cmp edx, WM_DESTROY
jne msg_command
mov ecx, NULL
call PostQuitMessage
xor rax,rax
jmp exit
msg_command:
cmp edx, WM_COMMAND
jne no_wm
cmp qword ptr [wParam], IDM_TEST
jne @F
xor r9d, r9d ; 4. argument: r9d = uType = 0
lea r8, [Testing] ; 3. argument: r8 = caption
lea rdx, [Text] ; 2. argument: edx = window text
xor rcx, rcx ; 1. argument: rcx = hWnd = NULL
call MessageBoxA
@@:
cmp qword ptr [wParam], IDM_HELLO
jne no_wm
xor r9d, r9d ; 4. argument: r9d = uType = 0
lea r8, [Hello] ; 3. argument: r8 = caption
lea rdx, [Text] ; 2. argument: edx = window text
xor rcx, rcx ; 1. argument: rcx = hWnd = NULL
call MessageBoxA
no_wm:
call DefWindowProcA
exit:
add rsp, 5*8
ret
align 4
WndProc endp
end
and RC file
#define IDM_TEST 1
#define IDM_HELLO 2
#define IDM_GOODBYE 3
#define IDM_EXIT 4
FirstMenu MENU
{
POPUP "&List"
{
MENUITEM "&Hello!",IDM_HELLO
MENUITEM "&Goodbye!", IDM_GOODBYE
MENUITEM SEPARATOR
MENUITEM "&Exit",IDM_EXIT
}
MENUITEM "&Test", IDM_TEST
}
Sources are quite big so debugging might be hard. If someone could post an example of compiling RC file and events services I'll be very greatful.
you simple forgot to pass hMenu to the call of CreateWindowEx.
There are two more issues in the window procedure:
- wParam's shadow space is accessed, but it has not been filled with R8. (You can use R8W to check the menu item IDs here)
- after the call to MsgBox, DefWindowProc is called with invalid arguments
;--------MAKE-------------------------------------------------------------
;rc menu_app.rc
;
;jwasm -win64 menu_app.asm
;
;link /SUBSYSTEM:WINDOWS menu_app.obj menu_app.res
;
;--------INCLUDES---------------------------------------------------------
includelib /WinInc/lib64/kernel32.lib
includelib /WinInc/lib64/user32.lib
includelib /WinInc/lib64/gdi32.lib
option casemap:none
;--------PROTOS-----------------------------------------------------------
HINSTANCE typedef QWORD
HWND typedef QWORD
HMENU typedef QWORD
HICON typedef QWORD
HBRUSH typedef QWORD
HCURSOR typedef QWORD
WPARAM typedef QWORD
LPARAM typedef QWORD
LPSTR typedef QWORD
LPVOID typedef QWORD
UINT typedef DWORD
NULL equ 0
WS_OVERLAPPEDWINDOW equ 0CF0000h
CW_USEDEFAULT equ 80000000h
SW_SHOWDEFAULT equ 10
SW_SHOWNORMAL equ 1
IDC_ARROW equ 32512
IDI_APPLICATION equ 32512
WM_DESTROY equ 2
CS_VREDRAW equ 1
CS_HREDRAW equ 2
COLOR_WINDOW equ 5
WM_COMMAND equ 111h
IDM_TEST EQU 1
IDM_HELLO EQU 2
IDM_GOODBYE EQU 3
IDM_EXIT EQU 4
proto_WNDPROC typedef proto :HWND,:UINT,:WPARAM,:LPARAM
WNDPROC typedef ptr proto_WNDPROC
WNDCLASSEXA struct 8
cbSize DWORD ?
style DWORD ?
lpfnWndProc WNDPROC ?
cbClsExtra DWORD ?
cbWndExtra DWORD ?
hInstance HINSTANCE ?
hIcon HICON ?
hCursor HCURSOR ?
hbrBackground HBRUSH ?
lpszMenuName LPSTR ?
lpszClassName LPSTR ?
hIconSm HICON ?
WNDCLASSEXA ends
POINT struct
x SDWORD ?
y SDWORD ?
POINT ends
MSG struct 8
hwnd HWND ?
message DWORD ?
wParam WPARAM ?
lParam LPARAM ?
time DWORD ?
pt POINT <>
MSG ends
GetModuleHandleA proto :LPSTR
GetCommandLineA proto
ExitProcess proto :UINT
LoadIconA proto :HINSTANCE, :LPSTR
LoadCursorA proto :HINSTANCE, :LPSTR
RegisterClassExA proto :ptr WNDCLASSEXA
CreateWindowExA proto :DWORD, :LPSTR, :LPSTR, :DWORD, :SDWORD, :SDWORD, :SDWORD, :SDWORD, :HWND, :HMENU, :HINSTANCE, :LPVOID
ShowWindow proto :HWND, :SDWORD
UpdateWindow proto :HWND
GetMessageA proto :ptr MSG, :HWND, :SDWORD, :SDWORD
TranslateMessage proto :ptr MSG
DispatchMessageA proto :ptr MSG
PostQuitMessage proto :SDWORD
DefWindowProcA proto :HWND, :UINT, :WPARAM, :LPARAM
EXTERN LoadMenuA :PROC
EXTERN MessageBoxA :PROC
;WinMain proto :HINSTANCE, :HINSTANCE, :LPSTR, :UINT
.data
ClassName db "SimpleWinClass",0
AppName db "Our First Window",0
MenuName db "FirstMenu",0
Text db "Message test",0
Testing db "test",0
Hello db "Hello!",0
MenuFailed db "LOAD MENU FAILED!",0
.data?
hInstance HINSTANCE ?
CommandLine LPSTR ?
hMenu dq ?
.code
WinMainCRTStartup proc FRAME
push rbp
.pushreg rbp
mov rbp,rsp
.setframe rbp, 0
.endprolog
sub rsp,32
mov ecx,NULL
call GetModuleHandleA
mov hInstance, rax
call GetCommandLineA
mov CommandLine, rax
mov rcx, hInstance
mov rdx, NULL
mov r8, CommandLine
mov r9d, SW_SHOWDEFAULT
call WinMain
mov ecx, eax
call ExitProcess
align 4
WinMainCRTStartup endp
WinMain proc FRAME
push rbp
.pushreg rbp
mov rbp,rsp
.setframe rbp, 0
sub rsp, sizeof WNDCLASSEXA + sizeof MSG + sizeof HWND + 13*8 ;make sure rsp is 16-byte aligned
.allocstack sizeof WNDCLASSEXA + sizeof MSG + sizeof HWND + 13*8
.endprolog
hInst equ <[rbp+10h]>
hPrevInst equ <[rbp+18h]>
CmdLine equ <[rbp+20h]>
CmdShow equ <[rbp+28h]>
wc equ <[rbp - sizeof WNDCLASSEXA].WNDCLASSEXA>
msg equ <[rbp - sizeof WNDCLASSEXA - sizeof MSG].MSG>
hwnd equ <[rbp - sizeof WNDCLASSEXA - sizeof MSG - sizeof HWND]>
mov hInst, rcx ;store param1 in shadow space
mov wc.cbSize, SIZEOF WNDCLASSEXA
mov wc.style, CS_HREDRAW or CS_VREDRAW
;mov rax, OFFSET WndProc ;using LEA is preferable
lea rax, [WndProc]
mov wc.lpfnWndProc, rax
mov wc.cbClsExtra, 0
mov wc.cbWndExtra, 0
mov wc.hInstance, rcx
mov wc.hbrBackground, COLOR_WINDOW+1
mov wc.lpszMenuName, 0
;mov rax, OFFSET ClassName ;using LEA is preferable
lea rax, [ClassName]
mov wc.lpszClassName, rax
mov ecx, NULL
mov edx, IDI_APPLICATION
call LoadIconA
mov wc.hIcon, rax
mov wc.hIconSm, rax
mov ecx, NULL
mov edx, IDC_ARROW
call LoadCursorA
mov wc.hCursor,rax
lea rcx, wc
call RegisterClassExA
lea rdx, [MenuName]
mov rcx, hInst
call LoadMenuA
mov hMenu, rax
mov ecx, NULL
lea rdx, [ClassName]
lea r8, [AppName]
mov r9d, WS_OVERLAPPEDWINDOW
mov dword ptr [rsp+4*8], CW_USEDEFAULT
mov dword ptr [rsp+5*8], CW_USEDEFAULT
mov dword ptr [rsp+6*8], CW_USEDEFAULT
mov dword ptr [rsp+7*8], CW_USEDEFAULT
mov qword ptr [rsp+8*8], NULL
mov rax,hMenu
mov qword ptr [rsp+9*8], rax
mov rax, hInst
mov [rsp+10*8], rax
mov qword ptr [rsp+11*8], NULL
call CreateWindowExA
mov hwnd,rax
mov rcx, hwnd
mov edx, SW_SHOWNORMAL
call ShowWindow
mov rcx, hwnd
call UpdateWindow
;--- message loop
@@:
lea rcx, msg
mov rdx, NULL
mov r8, 0
mov r9, 0
call GetMessageA
and rax, rax
jz @F
lea rcx, msg
call TranslateMessage
lea rcx, msg
call DispatchMessageA
jmp @B
@@:
mov rax, msg.wParam
add rsp, sizeof WNDCLASSEXA + sizeof MSG + sizeof HWND + 13*8
pop rbp
ret
align 4
WinMain endp
WndProc proc FRAME
sub rsp, 5*8
.allocstack 5*8
.endprolog
hWnd equ <[rbp+10h]>
uMsg equ <[rbp+18h]>
wParam equ <[rbp+20h]>
lParam equ <[rbp+28h]>
cmp edx, WM_DESTROY
jne msg_command
@pqm:
mov ecx, NULL
call PostQuitMessage
xor rax,rax
jmp exit
msg_command:
cmp edx, WM_COMMAND
jne no_wm
cmp r8w,IDM_EXIT
je @pqm
cmp r8w, IDM_TEST
jne @F
xor r9d, r9d ; 4. argument: r9d = uType = 0
lea r8, [Testing] ; 3. argument: r8 = caption
lea rdx, [Text] ; 2. argument: edx = window text
xor rcx, rcx ; 1. argument: rcx = hWnd = NULL
call MessageBoxA
jmp exit
@@:
cmp r8w, IDM_HELLO
jne no_wm
xor r9d, r9d ; 4. argument: r9d = uType = 0
lea r8, [Hello] ; 3. argument: r8 = caption
lea rdx, [Text] ; 2. argument: edx = window text
xor rcx, rcx ; 1. argument: rcx = hWnd = NULL
call MessageBoxA
xor eax,eax
jmp exit
no_wm:
call DefWindowProcA
exit:
add rsp, 5*8
ret
align 4
WndProc endp
end
another approach is to use "LoadMenu", followed by "SetMenu" (typically after window creation)
the method qWord gave is the way to go
just wanted to mention the "low-level" method so you'd know about it
sometimes, the programmer may switch from one menu to another with the basic method
still another method is to use LoadMenu and place the handle in the class structure
then, all windows of that class use the same menu
Now app works.
Quote from: qWord on November 27, 2013, 04:42:10 AM
- wParam's shadow space is accessed, but it has not been filled with R8. (You can use R8W to check the menu item IDs here)
Yes, I'm still doing 32-bit coding :biggrin:. I forgot, that R8 contains this parameter. I'm still having problems with understanding fastcall. Maybe when I get more knowlegde and experience I'll stop making bugs.
Thanks guys for replies.