;------------------------------------------------------------------ ; ; Hello64World2 - copyright Jeremy Gordon 2005-6 ; ; "HELLO WORLD" WINDOWS GDI PROGRAM - for 64 bits ; ; Assemble using GoAsm /x64 Hello64World2 ; ; Then link using:- ; GoLink Hello64World2.obj user32.dll kernel32.dll gdi32.dll ; GoLink automatically senses the type of file ; (add -debug coff if you want to watch the program in the debugger) ; ;------------------------------------------------------------------ ; ;***************** 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 ; DATA SECTION ; ALIGN 8 ;ensure all the following data elements are 8-byte aligned hDC DQ 0 ;to keep the handle of the device context PS PAINTSTRUCT ;***************** structure to hold message MSG DQ 0 ;+0 hWnd DD 0 ;+8 message DD 0 ;padding for next wParam DQ 0 ;+10 wParam DQ 0 ;+18 lParam DD 0 ;+20 time DD 0 ;+24 1st part of point structure DD 0 ;+28 2nd part of point structure DD 0 ;padding to bring total size to 48 bytes ;***************** structure to send to RegisterClass holding data WNDCLASS DD 1h+2h+40h ;+0 window class style (CS_VREDRAW+CS_HREDRAW+CS_CLASSDC) DD 0 ;padding for next DQ WndProcTable ;+8 pointer to Window Procedure DD 0 ;+10 no. of extra bytes to allocate after structure DD 0 ;+14 no. of extra bytes to allocate after window instance hInst DQ 0 ;+18 handle to instance containing window procedure DQ 0 ;+20 handle to the class icon hCursor DQ 0 ;+28 handle to the class cursor DQ 6 ;+30 identifies the class background brush (6=COLOR_WINDOW+1) DQ 0 ;+38 pointer to resource name for class menu DQ WINDOW_CLASSNAME ;+40 pointer to string for window class name ;******************** Window message table ; (in a real program this would deal with many more messages) MESSAGES DD (ENDOF_MESSAGES-$-4)/8 ;=number to be done DD 1h,CREATE,2h,DESTROY,0Fh,PAINT ENDOF_MESSAGES: ;label used to work out how many messages ;****************************************** ; WINDOW_CLASSNAME DB 'WC',0 ;string holding name of window class ; ;------------------------------------------------------------------ ; CODE SECTION ; ;******************* CREATE: ;one of the few messages dealt with by this prog XOR RAX,RAX ;return zero to make window RET ; DESTROY: ;one of the few messages dealt with by this prog INVOKE PostQuitMessage,0 ;exit via the message loop STC ;go to DefWindowProc too RET ; ;This paints an ellipse in the rectangle provided by Windows on the ;message WM_PAINT. This rectangle is the area which needs updating, eg ;on resizing or if the window is uncovered by another. PAINT: PUSH RDI,RBX ;save used non-volatile registers MOV RDI,RCX ;save hWnd for later use LEA RBX,PS ;keep paintstruct in rbx ARG RBX ;send it as a parameter ARG RDI ;hWnd INVOKE BeginPaint ;get device context to use, initialise paint MOV [hDC],RAX ;***************** use rectangle sent by system in paintstruct structure (PS) .. XOR RAX,RAX MOV EAX,[PS.bottom] ARG RAX MOV EAX,[PS.right] ARG RAX MOV EAX,[PS.top] ARG RAX MOV EAX,[PS.left] ARG RAX ARG [hDC] INVOKE Ellipse ;draw ellipse in update rectangle ;***************** INVOKE EndPaint,RDI,RBX ;rdi=hWnd, rbx=paintstruct POP RBX,RDI ;restore used non-volatile register XOR RAX,RAX ;return rax=0 and nc (don't call DefWindowProc) RET ; ;*************************************************************************** ;the call to the code label found in the table is not made to CALL [EAX+R10D*8+4] since ;all calls to addresses held in memory areas pointed to by registers or to addresses ;held in registers themselves are calls to 64-bit addresses in 64-bit assembly. ;But the table holds only 32-bit addresses. So instead we extract the 32-bit address in the ;table into R10D and then call R10 knowing that the high dword of R10 is zero. GENERAL_WNDPROC64: ;uMsg is in RDX (actually EDX) MOV R10D,[EAX] ;get number of messages to do ADD EAX,4 ;jump over size dword L2: DEC R10D JS >L3 ;message not found in table CMP [EAX+R10D*8],EDX ;see if its the correct message JNZ L2 ;no ;RCX=hwnd, RDX=uMsg, R8=wParam, R9=lParam PUSH R9,R8,RDX,RCX ;save the parameters for DefWindowProcA MOV R10D,[EAX+R10D*8+4] ;get the correct table procedure for the message CALL R10D POP RCX,RDX,R8,R9 ;restore the parameters for DefWindowProcA JNC >L4 ;nc=return value in eax - don't call DefWindowProc L3: SUB RSP,20h ;provide placeholders on stack for register params as reqd. CALL DefWindowProcA ADD RSP,20h ;restore stack after providing placeholders L4: RET ; ;*************************************************************************** ; ;******************* This is the actual window procedure WndProcTable: MOV EAX,ADDR MESSAGES ;give eax the list of messages to deal with CALL GENERAL_WNDPROC64 ;call the generic message handler (64-bit version) RET ; ;******************************************************************* START: INVOKE GetModuleHandleA,0 ;get handle to the process MOV [hInst],RAX ;record it in data label hInst INVOKE LoadCursorA,0,32512 ;get in eax, handle to IDC_ARROW (common arrow cursor) MOV [hCursor],RAX ;record it in data label hCursor (in WNDCLASS) ;********** now register the window class INVOKE RegisterClassA,ADDR WNDCLASS ;register the window class ;********** now create the window ARG 0,[hInst],0,0 ;owner=desktop ARG 200D ;height ARG 320D ;width ARG 50D,50D ;position y then x ARG 90000000h +0C00000h+40000h +80000h +20000h +10000h ;(POPUP+VISIBLE)+CAPTION+SIZEBOX+SYSMENU+MINIMIZEBOX+MAXIMIZEBOX ARG 'Hello 64 World window made by GoAsm' ;window title ARG ADDR WINDOW_CLASSNAME ;window class name ARG 0 ;extended style INVOKE CreateWindowExA ;make window ;************************ now enter the main message loop L1: INVOKE GetMessageA,ADDR MSG,0,0,0 OR RAX,RAX ;see if it is WM_QUIT JZ >L2 ;yes INVOKE TranslateMessage,ADDR MSG INVOKE DispatchMessageA,ADDR MSG JMP L1 ;after message dealt with, loop back for next one L2: ;message was WM_QUIT ARG [hInst],ADDR WINDOW_CLASSNAME INVOKE UnregisterClassA ;ensure class is removed INVOKE ExitProcess,[wParam] ;wParam=exit code