This version has new macros and some have been renamed and modified. The 2 register call macros have had an argument count guard added that tells you to use "invoke" if the arg count is over 4. Armed with a viable disassembly the stack frame technique is clear using ENTER and LEAVE mnemonics. To maintain spill space with the stack frame if no LOCAL variables are allocated, a dummy LOCAL variable is added using a MACRO ".stack" which can be omitted if any locals are allocated. Interestingly enough the extra LOCAL occurs at no mnemonic cost, it just changes the RBP address. The results are coming close to looking like normal code, the source follows.
NOTE that some of the macros have been modified and you need to use the "macros64.inc" file in the attached zip file.
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
OPTION DOTNAME
option casemap:none
include \masm64\include\temphls.inc
include \masm64\include\win64.inc
include \masm64\include\kernel32.inc
include \masm64\include\user32.inc
include \masm64\include\msvcrt.inc
includelib \masm64\lib\kernel32.lib
includelib \masm64\lib\user32.lib
includelib \masm64\lib\msvcrt.lib
OPTION PROLOGUE:rbpFramePrologue
OPTION EPILOGUE:rbpFrameEpilogue
include macros64.inc
.data
ClassName db "ML64_Window_Class",0
AppName db "ML64 Example Window",0
.data?
hInstance dq ?
hWnd dq ?
sWid dq ?
sHgt dq ?
hIcon dq ?
hCursor dq ?
hMnu dq ?
.code
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
entry_point proc
.stack
; -----------------
; set global values
; -----------------
mov hInstance, function(GetModuleHandle,0)
mov hIcon, function(LoadIcon,hInstance,10)
mov hCursor, function(LoadCursor,0,IDC_ARROW)
mov sWid, function(GetSystemMetrics,SM_CXSCREEN)
mov sHgt, function(GetSystemMetrics,SM_CYSCREEN)
call main
void(ExitProcess,0)
entry_point endp
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
main proc
.stack
LOCAL wc:WNDCLASSEX
mov wc.cbSize, SIZEOF WNDCLASSEX
mov wc.style, 0
mrm wc.lpfnWndProc, OFFSET WndProc
mov wc.cbClsExtra, 0
mov wc.cbWndExtra, 0
mrm wc.hInstance, hInstance
mrm wc.hIcon, hIcon
mrm wc.hCursor, hCursor
mov wc.hbrBackground, COLOR_BTNSHADOW+1
mrm wc.lpszMenuName, 0
mrm wc.lpszClassName, OFFSET ClassName
mrm wc.hIconSm, hIcon
void(RegisterClassEx, lp(wc))
; ------------------------------------------
; the following data allocations do not need
; to be placed at the start of the procedure
; ------------------------------------------
LOCAL64 lft
LOCAL64 top
LOCAL64 wid
LOCAL64 hgt
; ------------------------------------
; centred half height and width window
; ------------------------------------
mov rax, sWid
mov r11, rax
shr rax, 2
mov lft, rax
mov rax, r11
shr rax, 1
mov wid, rax
mov rax, sHgt
mov r11, rax
shr rax, 2
mov top, rax
mov rax, r11
shr rax, 1
mov hgt, rax
invoke CreateWindowEx,0,ADDR ClassName,ADDR AppName,\
WS_OVERLAPPEDWINDOW or WS_VISIBLE,\
lft,top,wid,hgt,0,0,hInstance,0
mov hWnd, rax
mov hMnu, function(LoadMenu,hInstance,100)
void(SetMenu,hWnd,hMnu)
call msgloop
ret
main endp
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
msgloop proc
.stack
LOCAL msg :MSG
LOCAL64 _rsi ; allocate QWORD
LOCAL64 _rdi ; allocate QWORD
mov _rsi, rsi ; preserve rsi
mov _rdi, rdi ; preserve rdi
xor rsi, rsi ; zero rsi
lea rdi, msg ; load rdi with structure address
jmp get_msg ; jump into loop
lpstart:
void(TranslateMessage,rdi)
void(DispatchMessage,rdi)
get_msg:
test rax, function(GetMessage,rdi,rsi,rsi,rsi)
jnz lpstart
mov rdi, _rdi ; restore rdi
mov rsi, _rsi ; restore rsi
ret
msgloop endp
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
WndProc proc
.stack
r2m hWin, rcx
r2m uMsg, rdx
r2m wParam, r8
r2m lParam, r9
.if uMsg == WM_COMMAND
.if wParam == 1000
void(SendMessage,hWin,WM_SYSCOMMAND,SC_CLOSE,NULL)
.elseif wParam == 10000
void(MessageBox,hWin,txt("Example with icon, manifest and menu."),txt("About ML64 Example"),MB_OK)
.endif
.elseif uMsg == WM_CLOSE
void(MessageBox,0,txt("Sending the WM_DESTROY message."),txt("WM_CLOSE here"),MB_OK)
void(SendMessage,hWin,WM_DESTROY,0,0)
.elseif uMsg == WM_DESTROY
void(PostQuitMessage,NULL)
.endif
void(DefWindowProc,hWin,uMsg,wParam,lParam)
ret
WndProc endp
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
end
Steve,
Curious on why you use cvtres.
The linker I am using 14.00.23506.0 adds the .res file just fine??
James
James,
Probably sheer habit. From memory link needs cvtres if you add the RES file instead of converting it so there is no real gain.