Hey guys,
I am having this DialogBox on which I have an DIBSection. The problem is that on 64 bit it keeps eating up memory. It keeps increasing the memory while no other programs are running. Compiling it 32 bit all works perfectly fine.
I've read that the PaintStruct and the Message structures are increased in size, but also that the window handle is now assumed to be a qword instead of a dword.
Consider the following code:
;this links in necessary imports
#Define LINKFILES
;comment this if building for 32bit
#Define WIN64
;windows.h which includes various other .h's
#Include "\GoAsm\include\windows.h"
#Include "\GoAsm\macros\Macros.asm"
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Const Section
ScreenWidth Equ 400
ScreenHeight Equ 300
DialogAlign Equ 600
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Data Section
hInstance DQ ?
canvasDC DQ ?
canvasBmp DQ ?
hDC DQ ?
canvas_buffer DQ ?
clip1 DQ ?
clip2 DQ ?
;***************** structure to hold stuff from Windows on WM_PAINT (64-bit version)
PAINTSTRUCT STRUCT
DQ 0 ;+0 hDC
DD 0 ;+8 fErase
left DD 0 ;+C left )
top DD 0 ;+10 top ) RECT
right DD 0 ;+14 right )
bottom DD 0 ;+18 bottom )
DD 0 ;+1C fRestore
DD 0 ;+20 fIncUpdate
DB 32 DUP 0 ;+24 rgbReserved
DD 0 ;padding to bring total size to 72 bytes
ENDS
PS PAINTSTRUCT
canvas BITMAPINFO <>
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
DATA? Section
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Code Section
START:
Invoke GetModuleHandle, 0
Mov [hInstance], Rax
Invoke DialogBoxParam, [hInstance], 101, 0, Offset WndProc, 0
Invoke ExitProcess, 0
WndProc Frame hWin, uMsg, wParam, lParam --> I think a big problem lies here. It compiles saying that hWin is dword instead of Qword, how do I get it into a qword? same goes for wParam and lParam.
Cmp D[uMsg], WM_INITDIALOG
Jne > Wm_2
Push DialogAlign
mov D[canvas.bmiHeader.biSize],sizeof BITMAPINFOHEADER
mov D[canvas.bmiHeader.biWidth],ScreenWidth
mov D[canvas.bmiHeader.biHeight],-ScreenHeight
mov W[canvas.bmiHeader.biPlanes],1
mov W[canvas.bmiHeader.biBitCount],32
Pop Rax
; Setup DibSection.
Invoke GetDC, [hWin]
Mov [hDC], Rax
Invoke CreateCompatibleDC, Rax
Mov [canvasDC], Rax
Invoke CreateDIBSection, [hDC], Offset canvas, DIB_RGB_COLORS, Offset canvas_buffer, 0, 0
Mov [canvasBmp], Rax
Invoke SelectObject, [canvasDC], Rax
Invoke ReleaseDC, [hDC], 0
Invoke SetTimer, [hWin], 1, 0, 0
Wm_2:
Cmp D[uMsg], WM_TIMER
Jnz > Wm_3
Mov Rdi, [canvas_buffer]
Mov Rcx, ScreenWidth * ScreenHeight
Xor Rax, Rax
Rep Stosd
;--- drawing functions...
Mov Rdi, [canvas_buffer]
Invoke RedrawWindow, [hWin], 0, 0, RDW_INVALIDATE
Wm_3:
Cmp D[uMsg], WM_PAINT
Jnz > Wm_4
Mov Rax, [hWin]
Mov Rcx, Offset PS
Push Rcx
Push Rax
Invoke BeginPaint, Rax, Rcx
Invoke BitBlt, Rax, 0, 0, ScreenWidth, ScreenHeight, [canvasDC], 0, 0, SRCCOPY
Call EndPaint
Wm_4:
Cmp D[uMsg], WM_CLOSE ; Did we press the close button
Jne > Wm_5
Invoke EndDialog, [hWin], 0
Wm_5:
Cmp D[uMsg], WM_LBUTTONDOWN
Jnz > Wm_6
Invoke SendMessage, [hWin], WM_NCLBUTTONDOWN, HTCAPTION, NULL
Wm_6:
Xor Rax, Rax
Ret
EndF
Cmp D[uMsg], WM_PAINT
Jnz > Wm_4
Mov Rax, [hWin]
Mov Rcx, Offset PS
Push Rcx
Push Rax
Invoke BeginPaint, Rax, Rcx
Invoke BitBlt, Rax, 0, 0, ScreenWidth, ScreenHeight, [canvasDC], 0, 0, SRCCOPY
Call EndPaint
The problem appears to be that you are not properly closing your BeginPaint which will lead to huge resource leaks. Win64 uses FASTCALL, when you push the parameters on the stack then later call EndPaint without parameters (because they are already on the stack) that is STDCALL. You must either mov them into the appropriate registers or pop them and use INVOKE. In FASTCALL the first two parameters are passed in ECX and EDX respectively so you could use those registers since you're already moving the data into registers (though the ones your using are not the correct ones and invoke is preferable).
Cmp D[uMsg], WM_PAINT
Jnz > Wm_4
Mov Rcx, [hWin]
Mov Rdx, Offset PS
Push Rdx
Push Rcx
Call BeginPaint
Invoke BitBlt, Rax, 0, 0, ScreenWidth, ScreenHeight, [canvasDC], 0, 0, SRCCOPY
Pop Rcx
Pop Rdx
Call EndPaint
That said, you are always better off to use INVOKE, that way you don't have to deal with parameter order (which changes) or remember the registers used in FASTCALL.
Cmp D[uMsg], WM_PAINT
Jnz > Wm_4
invoke BeginPaint, [hWin], Offset PS
Invoke BitBlt, Rax, 0, 0, ScreenWidth, ScreenHeight, [canvasDC], 0, 0, SRCCOPY
Invoke EndPaint, [hWin],Offset PS
Edgar
As an addendum to this thread, I should also note that when you are translating WIN32 to WIN64 you must always make note of any CALL instruction and be sure to understand the code leading up to it. Since many WIN32 assembly programmers used parameters already on the stack to pass arguments to a CALL instruction as in the code above, you have to make sure you catch and rewrite those sequences. Also when writing WIN32 programs that you might later want to port to WIN64 you have to avoid this behavior. I am equally as guilty of the push/call method though I now try to avoid it like the plague. For a programming trick that has the potential of saving a microsecond of runtime, you can make the transition to 64 bit a living hell, the moral is ALWAYS USE INVOKE !, GoAsm will use the correct calling convention and even perform some optimization if applicable.
Many thanks for this lesson donkey. When I translated the 32 bit source, I totally forgot about win64 calling conventions. Thanks for the heads up.