WM_DESTROY x64 Windows 汇编程序中的 WndProc 未收到消息



我正在尝试使用MASM/w Visual Studio 2019重新创建类似于以下C++代码的东西。基本上在这个阶段,只希望窗口是可移动的,关闭按钮可以工作。

#include <iostream>
#include <Windows.h>
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM
lParam)
{
switch (message)
{
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
int main()
{
wchar_t windowclass[] = L"MyWinTest";
HINSTANCE hInstance = GetModuleHandleW(NULL);
MSG msg;
WNDCLASSEXW wc;
wc.cbSize = sizeof(WNDCLASSEX);
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hbrBackground = 0;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hIcon = LoadIcon(hInstance, IDI_APPLICATION);
wc.hIconSm = NULL;
wc.hInstance = hInstance;
wc.lpfnWndProc = WndProc;
wc.lpszClassName = windowclass;
wc.lpszMenuName = nullptr;
wc.style = CS_HREDRAW | CS_VREDRAW;

RegisterClassExW(&wc);
HWND hWnd = CreateWindowExW(
0, 
windowclass,
L"MyWindow",
WS_OVERLAPPEDWINDOW, 
CW_USEDEFAULT, 
CW_USEDEFAULT,
800, 
600, 
NULL, 
NULL, 
hInstance, 
NULL);
ShowWindow(hWnd, SW_SHOW);
UpdateWindow(hWnd);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}

在我的使用 MASM 的 x64 程序集版本中,窗口被创建并显示,WndProc 也被击中,可以看到它收到消息WM_CREATE并WM_PAINT但窗口无法移动且无法关闭。我确实将C++版本编译为 x64 并输出程序集列表进行比较,但据我所知,它看起来与程序集版本非常相似。

WSTR MACRO lbl:req,qstr:VARARG
LOCAL arg,unq,qot,q
lbl LABEL WORD
FOR arg,<qstr>
qot SubStr <arg>,1,1
q = 0
IFIDNI qot,<!'>;'
q = 1
ELSEIFIDNI qot,<!">;"
q = 1
ELSE
DW arg
ENDIF
IF q EQ 1
unq SubStr <arg>,2,@SizeStr(<arg>)-2
%   FORC c,<unq>
DW "&c"
ENDM
ENDIF
ENDM
DW 0
ENDM
L MACRO qstr:VARARG
LOCAL sym,seg
seg EQU <.code>
%IFIDNI <@CurSeg>,<_DATA>
seg EQU <.data>
ENDIF
.CONST
ALIGN 4
WSTR sym,qstr
seg
EXITM <OFFSET sym>
ENDM
extrn   LoadCursorW: PROC
extrn   MessageBoxW: PROC
extrn   ExitProcess: PROC
extrn   GetModuleHandleW: PROC
extrn   RegisterClassExW: PROC
extrn   CreateWindowExW: PROC
extrn   GetLastError: PROC
extrn   DefWindowProcW: PROC
extrn   ShowWindow: PROC
extrn   Sleep: PROC
extrn   GetMessageW: PROC
extrn   TranslateMessage: PROC
extrn   DispatchMessageW: PROC
extrn   DestroyWindow: PROC
extrn   UpdateWindow: PROC
extrn   PostQuitMessage: PROC
extrn   BeginPaint: PROC
extrn   EndPaint: PROC
.data
wstr windowClassName,"AsmTestClass",0,0
wstr windowTitle,"AsmTest",0,0
HWND_DESKTOP        textequ <0h>
MB_OK           textequ <0h>
INFINITE            textequ <0ffffffffh>
WM_CREATE       textequ <0001h>
WM_DESTROY      textequ <0002h>
WM_SIZE         textequ <0005h>
WM_PAINT        textequ <000fh>
WM_CLOSE            textequ <0010h>
WM_QUIT         textequ <0012h>
SW_HIDE         textequ <0000h>
SW_SHOW         textequ <0005h>
CS_VREDRAW      textequ <0001h>
CS_HREDRAW      textequ <0002h>
WS_OVERLAPPED   textequ <00000000h>
WS_CAPTION      textequ <00c00000h>
WS_SYSMENU      textequ <00080000h>
WS_MINIMIZEBOX  textequ <00020000h>
CW_USEDEFAULT   textequ <80000000h>
IDI_APPLICATION textequ <00007f00h>
WINDOW_WIDTH        DWORD   800
WINDOW_HEIGHT   DWORD   600
WNDCLASSEX STRUCT DWORD
cbSize          DWORD   ?
style           DWORD   ?
lpfnWndProc     QWORD   ?
cbClsExtra      DWORD   ?
cbWndExtra      DWORD   ?
hInstance       QWORD   ?
hIcon           QWORD   ?
hCursor         QWORD   ?
hbrBackground   QWORD   ?
lpszMenuName    QWORD   ?
lpszClassName   QWORD   ?
hIconSm         QWORD   ?
WNDCLASSEX ENDS
MSG STRUCT 
hwnd                QWORD   ?
message         DWORD   ?
wParam          QWORD   ?
lParam          QWORD   ?
time                DWORD   ?
x               DWORD   ?
y               DWORD   ?
MSG ENDS
PAINTSTRUCT STRUCT 8
hdc             QWORD   ?
fErase          DWORD   ?
left                DWORD   ?
top             DWORD   ?
right           DWORD   ?
bottom          DWORD   ?
fRestore            DWORD   ?
fIncUpdate      DWORD   ?
rgbReserved     BYTE        32 DUP (?)
PAINTSTRUCT ENDS
.code
main proc
LOCAL wc:WNDCLASSEX
LOCAL hWnd:QWORD
LOCAL hInstance:QWORD
LOCAL hCursor:QWORD
LOCAL ATOM:WORD
LOCAL message:MSG

sub     rsp, 8
; hInstance = GetModuleHandle(NULL)
mov     rcx, 0
call        GetModuleHandleW
mov     hInstance, rax
; hCursor = LoadCursor(NULL,IDI_APPLICATION)
mov     edx, IDI_APPLICATION
xor     ecx, ecx
call        LoadCursorW
mov     hCursor, rax

; Setup Window Class
mov     wc.cbSize, SIZEOF WNDCLASSEX
mov     wc.style, CS_VREDRAW or CS_HREDRAW
lea     rax, OFFSET WndProc
mov     wc.lpfnWndProc, rax
mov     wc.cbClsExtra, 0
mov     wc.cbWndExtra, 0
lea     rax, hInstance
mov     wc.hInstance, rax
mov     wc.hbrBackground, 0
mov     wc.lpszMenuName, 0
lea     rax, hCursor
mov     wc.hCursor, rax
lea     rax, windowClassName
mov     wc.lpszClassName, rax
mov     wc.hIconSm, 0
lea     rcx, wc
call        RegisterClassExW
mov     ATOM, ax
; CreateWindowExW
mov     QWORD PTR [rsp+88], 0               ;   lpParam
lea     rax, hInstance
mov     QWORD PTR [rsp+80], rax             ;   hInstance
mov     QWORD PTR [rsp+72], 0               ;   hMenu
mov     QWORD PTR [rsp+64], 0               ;   hWndParent
mov     edx, WINDOW_HEIGHT
mov     DWORD PTR [rsp+56], edx             ;   nHeight
mov     edx, WINDOW_WIDTH
mov     DWORD PTR [rsp+48], edx             ;   nWidth
mov     DWORD PTR [rsp+40], CW_USEDEFAULT   ;   Y
mov     DWORD PTR [rsp+32], CW_USEDEFAULT   ;   X
mov     r9d, WS_OVERLAPPED or WS_CAPTION or WS_SYSMENU or WS_MINIMIZEBOX        ; dwStyle
lea     r8, windowTitle                     ;   lpWindowName
lea     rdx, windowClassName                    ;   lpClassName
xor     ecx,ecx                             ;   dwExStyle
call        CreateWindowExW
cmp     rax,  0
je      WindowFailed
jmp     WindowSuccess
WindowFailed:
call        GetLastError
; to-do check error ?
WindowSuccess:
mov     hWnd, rax
mov     rcx, hWnd       ; hWnd
mov     edx, SW_SHOW        ; nCmdShow
call        ShowWindow
mov     rcx, hWnd       ; hWnd
call        UpdateWindow
MessageLoop:
xor     r9d, r9d            ; wMsgFilterMax
xor     r8d, r8d            ; wMsgFilterMin
xor     edx, edx            ; hWnd
lea     rcx, message        ; lpMsg
call        GetMessageW
test        eax, eax
je      QuitMessageLoop
lea     rcx, message            ; lpMsg
call    TranslateMessage
lea     rcx, message            ; lpMsg
call        DispatchMessageW

jmp     MessageLoop 
QuitMessageLoop: 
mov     ecx, eax                            ; uExitCode
call        ExitProcess
main endp
WndProc proc
LOCAL hWnd:QWORD
LOCAL uMsg:DWORD
LOCAL wParam:QWORD
LOCAL lParam:QWORD
LOCAL result:QWORD
LOCAL ps:PAINTSTRUCT
LOCAL hdc:QWORD
sub     rsp, 8
mov     lParam, r9
mov     wParam, r8
mov     uMsg, edx
mov     hWnd, rcx

; msg handler
cmp     uMsg,WM_CREATE
je      create
cmp     uMsg,WM_PAINT
je      paint   
cmp     uMsg,WM_DESTROY
je      destroy
; default
mov     r9, lParam
mov     r8, wParam
mov     edx, uMsg
mov     rcx, hWnd
call        DefWindowProcW
mov     result,rax
jmp     finish
create:
mov     result, 0
jmp     finish
paint:
mov     rcx, hWnd
lea     rdx, ps
call        BeginPaint
mov     hdc, rax
; to-do HDC paint stuff here
mov     rcx, hWnd
lea     rdx, ps
call        EndPaint
mov     result, 0
jmp     finish
destroy:
xor     ecx, ecx            ; nExitCode
call        PostQuitMessage
mov     result, 0
jmp     finish
finish: 
mov     rax, result

ret 
WndProc endp
End

注意由于本地语句 masm 在子 rsp,8 之前自动添加到我的主:(-152 + -8 = -160)

push    rbp
mov     rbp, rsp
add     rsp, 0FFFFFFFFFFFFFF68h

并添加到 WNDPROC 例程 (-120 + -8 = -128)

push    rbp
mov     rbp, rsp
add     rsp, 0FFFFFFFFFFFFFF88h
...
leave

代码错误 - 在两个过程中 -

sub rsp, 8

当从 x64 调用约定

调用方

负责为被调用方的参数分配空间。调用方必须始终分配足够的空间来存储 四个寄存器参数,即使被调用方不需要那么多 参数。

所以需要 - 存储四个寄存器参数 - 4*8 和 +8 用于 16 字节对齐,所以

sub rsp, 40

在具体情况下,对DispatchMessageWTranslateMessage的调用可能会损坏(覆盖)message,因为它位于被调用方的参数空间中。 如果在调试器下进行测试 - 我认为DispatchMessageW覆盖 Prolog 中的message,而不是已经使用了错误的message

相关内容

  • 没有找到相关文章

最新更新