Я пытаюсь создать окно в NASM и столкнулся с проблемой при вызове CreateWindowExW. Кажется, он получает неправильные параметры.
Это (соответствующий) код для window.asm
SetupWindow:
; Stack setup
push rbp
mov rbp, rsp
push r12
push r13
; Variables
sub rsp, sizeof(WNDCLASSEXW)
; Clear WNDCLASSEXW
cld
mov r12, rsp
mov rdi, r12
xor eax, eax
mov ecx, sizeof(WNDCLASSEXW)
rep stosb
; Set WNDCLASSEXW fields
mov r13, sizeof(WNDCLASSEXW) ; sizeof(WNDCLASSEXW) -> cbSize
mov dword [r12 + WNDCLASSEXW.cbSize], r13d
lea r13, [rel WindowProcedure] ; WindowProcedure -> lpfnWndProc
mov qword [r12 + WNDCLASSEXW.lpfnWndProc], r13
lea r13, [rel className] ; className -> lpszClassName
mov qword [r12 + WNDCLASSEXW.lpszClassName], r13
; GetModuleHandleA(NULL) -> hInstance
sub rsp, 32
xor eax, eax
call GetModuleHandleA
add rsp, 32
mov qword [r12 + WNDCLASSEXW.hInstance], rax
; RegisterClassExW
sub rsp, 32 ; Shadow space
mov rcx, r12 ; Window class structure
call RegisterClassExW
add rsp, 32 ; Clear shadow space
; CreateWindowExW
sub rsp, 80
xor ecx, ecx ; No extended styles
mov rdx, qword [r12 + WNDCLASSEXW.lpszClassName]
lea r8, [rel windowName] ; Window name
mov r9, WS_OVERLAPPEDWINDOW ; Generic window style
mov r13, CW_USEDEFAULT ; CW_USEDEFAULT for X, Y, nWidth, nHeight
mov qword [rsp + 32 + 0], r13 ; X
mov qword [rsp + 32 + 8], r13 ; Y
mov qword [rsp + 32 + 16], r13 ; nWidth
mov qword [rsp + 32 + 24], r13 ; nHeight
mov qword [rsp + 32 + 32], rcx ; hWndParent
mov qword [rsp + 32 + 40], rcx ; hMenu
mov r13, qword [r12 + WNDCLASSEXW.hInstance]
mov qword [rsp + 32 + 48], r13 ; hInstance
mov qword [rsp + 32 + 56], rcx ; lpParam
call CreateWindowExW2
add rsp, 80
; Check window
cmp rax, 0
jne .success
.error:
sub rsp, 32
call GetLastError
add rsp, 32
mov ecx, eax
call ExitProcess
.success:
mov [rel window], rax
mov rcx, [rel window]
mov edx, SW_SHOWNORMAL
call ShowWindow
и это код для win32.inc:
; kernel32
extern ExitProcess
extern GetLastError
extern GetModuleHandleA
; user32
extern CreateWindowExW
extern RegisterClassExW
extern ShowWindow
struc WNDCLASSEXW
.cbSize: resd 1
.style: resd 1
.lpfnWndProc: resq 1
.cbClsExtra: resd 1
.cbWndExtra: resd 1
.hInstance: resq 1
.hIcon: resq 1
.hCursor: resq 1
.hbrBackground: resq 1
.lpszMenuName: resq 1
.lpszClassName: resq 1
.hIconSm: resq 1
endstruc
%define CW_USEDEFAULT 80000000h
%define SW_SHOWNORMAL 1
%define WS_CAPTION 00C00000h
%define WS_MAXIMIZEBOX 00010000h
%define WS_MINIMIZEBOX 00020000h
%define WS_OVERLAPPED 00000000h
%define WS_SYSMENU 00080000h
%define WS_THICKFRAME 00040000h
%define WS_OVERLAPPEDWINDOW (WS_CAPTION | WS_MAXIMIZEBOX | WS_MINIMIZEBOX | \
WS_OVERLAPPED | WS_SYSMENU | WS_THICKFRAME)
Полный код находится на GitHub: https://github.com/MobSlicer152/pong
RCX, RDX, R8 и R9 присваиваются 0, класс окна, заголовок окна и стиль.
Я понял, что у меня порядок наоборот, и я не включил теневое пространство в смещения. Однако теперь CreateWindowExW возвращает NULL, а GetLastError возвращает 0.





Я понял, что я сделал не так. По сути, я думал, что после четырех параметров регистра это то же самое, что и соглашение о вызовах X86. Однако это не так. Целочисленные параметры идут в порядке слева направо и дополняются до 8 байт. Кажется, что внесение этого изменения решило мою проблему.
Однако затем функция начала возвращать NULL, но GetLastError возвращала 0 (ERROR_SUCCESS).
Я решил это. Я понял, что CreateWindow терпит неудачу, если оконная процедура возвращает false при обработке сообщения WM_NCCREATE, которое она получает во время CreateWindow. Я изменил его, чтобы он возвращал true, и теперь это удалось.
«CreateWindow завершается с ошибкой, если оконная процедура возвращает false» — большинство оконных сообщений возвращают 0 в случае успеха, если не указано иное. Создание окна завершается неудачно, если WM_NCCREATE возвращает 0 (ложь), вместо этого он должен возвращать 1 (истина). Но последующий WM_CREATE должен возвращать 0. Правильный подход состоит в том, чтобы ваша оконная процедура вызывала DefWindowProc() для любого сообщения, которое она не обрабатывает явно, и возвращала все, что возвращает `DefWindowProc().
Это хорошее разъяснение
Ваш вопрос кажется довольно хорошим, но люди ценят «минимальный, воспроизводимый пример», для которого требуются полные исходные коды программы, а также команды, которые вы используете для сборки программы. См. stackoverflow.com/help/minimal-reproducible-example