Ok... the same example for Win64 using mingw64:
Sorry, there are some comments in portuguese (pt_BR)...
; winapp.asm
; NASM code for win64
bits 64
default rel
%include "win64.inc"
section .data
winapp_class: db `MyWinAppClass\0`
winapp_title: db `My Windows App\0`
msg_caption: db `Error\0`
msg_text: db `Error creating main window.\0`
wc: istruc WNDCLASS
at WNDCLASS.style, dd (CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS)
at WNDCLASS.hbrBackground, dd (COLOR_WINDOW+1)
iend
msg: istruc MSG
iend
section .bss
hWnd: resd 1
nCmdShow: resd 1
section .text
; Imported from kernel32.exe & user32.exe
extern __imp_LoadIconA
extern __imp_LoadCursorA
extern __imp_RegisterClassA
extern __imp_CreateWindowExA
extern __imp_MessageBoxA
extern __imp_UpdateWindow
extern __imp_ShowWindow
extern __imp_GetMessageA
extern __imp_TranslateMessage
extern __imp_DispatchMessageA
extern __imp_DefWindowProcA
extern __imp_PostQuitMessage
;===============================
; Win64 calling convention:
; RCX, RDX, R8 and R9 are used for the first 4 arguments,
; any others goes to stack
;===============================
align 16
global _WindowMessagesHandler
; Entry: ECX = hWnd,
; EDX = uMsg
; R8D = wParam
; R9D = lParam (yep... dword).
_WindowMessagesHandler:
cmp edx,WM_DESTROY
jz Handle_Destroy
; All registers are already in place!
call qword [__imp_DefWindowProcA]
ret
Handle_Destroy:
xor ecx,ecx
call qword [__imp_PostQuitMessage]
xor eax,eax
HandlerExit:
ret
align 16
global WinMain
; Entry: ECX = hInstance,
; EDX = hPrevInstance
; R8 = lpszCmdLine
; R9D = nCmdShow
WinMain:
;-----------------
; Registra a classe de janela.
;-----------------
mov [wc+WNDCLASS.hInstance],ecx
mov [nCmdShow],r9d ; salva nCmdShow
xor ecx,ecx
mov edx,IDI_APPLICATION
call qword [__imp_LoadIconA]
mov [wc+WNDCLASS.hIcon],eax
xor ecx,ecx
mov edx,IDC_ARROW
call qword [__imp_LoadCursorA]
mov [wc+WNDCLASS.hCursor],eax
lea rax,[_WindowMessagesHandler]
mov [wc+WNDCLASS.lpWndProc],rax
lea rax,[winapp_class]
mov [wc+WNDCLASS.lpszClassName],rax
lea rcx,[wc]
call qword [__imp_RegisterClassA]
;-----------------
; Cria a nova janela.
;-----------------
xor ecx,ecx
lea rdx,[winapp_class]
lea r8,[winapp_title]
mov r9d,WS_OVERLAPPEDWINDOW
; Todos os outros parĂ¢metros na pilha (C style)
push 0
mov eax,[wc+WNDCLASS.hInstance]
push rax
push 0
push 0
push 480
push 640
push CW_USEDEFAULT ; nasm warning: Ignore it!
push CW_USEDEFAULT ; nasm warning: Ignore it!
call qword [__imp_CreateWindowExA]
test eax,eax
jnz created_ok
;----
; Em caso de erro com __imp_CreateWindowEx...
;----
xor ecx,ecx
lea rdx,[msg_text]
lea r8,[msg_caption]
mov r9d,(MB_OK | MB_ICONERROR)
call qword [__imp_MessageBoxA]
xor eax,eax
jmp WinMainExit
;----
; Tudo ocorreu bem com __imp_CreateWindowEx...
;----
created_ok:
mov [hWnd],eax ; Salva o handle.
;---- __imp_Update and Show...
mov ecx,eax
call qword [__imp_UpdateWindow]
mov ecx,[hWnd]
mov edx,[nCmdShow]
call qword [__imp_ShowWindow]
MessageLoop:
mov ecx,[hWnd]
lea rdx,[msg]
xor r8d,r8d
xor r9d,r9d
call qword [__imp_GetMessageA]
test eax,eax
jz ExitLoop
lea rcx,[msg]
call qword [__imp_TranslateMessage]
lea rcx,[msg]
call qword [__imp_DispatchMessageA]
jmp MessageLoop
ExitLoop:
mov eax,[msg+MSG.wParam]
WinMainExit:
ret
Notice that our functions don't deal with the stack (they have 4 arguments, allocated on RCX, RDX, R8 and R9 only)... This allow us to use a simple RET... Only pointers must be 8 bytes long. Handles are still DWORDs (Win64 uses IL32P64 standard)... When we have to put arguments on stack (before calling CreateWindowExA), this must be done in C style (last argument first), but the 4 first arguments must (if integers) must be passed on RCX,RDX,R8 and R9 registers.
All Win64 API calls are still indirect...
; win64.inc
%define CS_VREDRAW 1
%define CS_HREDRAW 2
%define CS_DBLCLKS 8
%define COLOR_WINDOW 5
%define WM_DESTROY 2
%define IDI_APPLICATION 32512
%define IDC_ARROW 32512
%define CW_USEDEFAULT 0x80000000
%define WS_OVERLAPPED 0x000000
%define WS_CAPTION 0xc00000
%define WS_SYSMENU 0x080000
%define WS_THICKFRAME 0x040000
%define WS_MINIMIZEBOX 0x020000
%define WS_MAXIMIZEBOX 0x010000
%define WS_OVERLAPPEDWINDOW (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX)
%define MB_OK 0
%define MB_ICONERROR 0x10
struc WNDCLASS
.style: resd 1
.lpWndProc: resq 1 ; ptrs are 8 bytes long.
.cbClsExtra: resd 1
.cbWndExtra: resd 1
.hInstance: resd 1
.hIcon: resd 1
.hCursor: resd 1
.hbrBackground: resd 1
.lpszMenuName: resq 1 ; ptrs are 8 bytes long.
.lpszClassName: resq 1 ; ptrs are 8 bytes long.
endstruc
struc MSG
.hWnd: resd 1
.message: resd 1
.wParam: resd 1
.lParam: resd 1
.time: resd 1
.pt: resd 2
endstruc
# Makefile
CC=x86_64-w64-mingw32-gcc
.PHONY: all clean
all: winapp.exe
winapp.exe: winapp.o
$(CC) -O3 -s -o $@ $^
# -f win64 is necessary!
winapp.o: winapp.asm win64.inc
nasm -f win64 -o $@ $<
clean:
-rm *.o
When using winsock2 you have to declare __imp_WSAStartup (no A or W, 'cause there are no string arguments) as external, use RCX and RDX as arguments and call it indirectly... You have also to link libwsock32 adding -lwsock32 to the linker.