;------------------------------------------------------------------
;
; HelloWorld2 - copyright Jeremy Gordon 2002-2003
;
; SIMPLE "HELLO WORLD" WINDOWS GDI PROGRAM - for GoAsm
;
; Assemble using GoAsm HelloWorld2 (produces PE COFF file)
; Then link using:-
; GoLink HelloWorld2.obj user32.dll kernel32.dll gdi32.dll
; (add -debug coff if you want to watch the program in the debugger)
;
;------------------------------------------------------------------
;
DATA SECTION
;
hInst DD 0 ;to keep the handle to the process itself
hDC DD 0 ;to keep the handle of the device context
PAINTSTRUCT DD 16 DUP 0 ;structure to hold stuff from Windows on WM_PAINT
MSG DD 7 DUP 0 ;structure to hold messages from Windows as follows:-
;hwnd, +4=message, +8=wParam, +C=lParam, +10h=time, +14h/18=pt
WNDCLASS DD 10D DUP 0 ;structure to send to RegisterClass holding data:-
;+0 window class style (CS_)
;+4 pointer to Window Procedure
;+8 no. of extra bytes to allocate after structure
;+C no. of extra bytes to allocate after window instance
;+10 handle to instance of this window class
;+14 handle to the class icon
;+18 handle to the class cursor
;+1C identifies the class background brush
;+20 pointer to resource name for class menu
;+24 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 to hold name of window class
;
;------------------------------------------------------------------
;
CODE SECTION
;
INITIALISE_WNDCLASS: ;get ready for window
MOV EBX,ADDR WNDCLASS
MOV EAX,9
L1:
MOV D[EBX+EAX*4],0 ;fill it with zeroes
DEC EAX
JNS L1
;***** add things to window class for all windows in the program ..
MOV EAX,[hInst] ;get handle to the process
MOV [EBX+10h],EAX ;make it the window class
MOV D[EBX+1Ch],6D ;set background brush to COLOR_WINDOW+1
RET
;
;*******************
CREATE: ;one of the few messages dealt with by this prog
XOR EAX,EAX ;return zero to make window
RET
;
DESTROY: ;one of the few messages dealt with by this prog
PUSH 0
CALL PostQuitMessage ;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:
MOV EBX,ADDR PAINTSTRUCT
PUSH EBX,[EBP+8h] ;EBP+8h=hwnd
CALL BeginPaint ;get device context to use, initialise paint
MOV [hDC],EAX
PUSH [EBX+14h],[EBX+10h] ;rectangle bottom, right
PUSH [EBX+0Ch],[EBX+8h] ;rectangle top, left
PUSH [hDC]
CALL Ellipse ;draw ellipse in update rectangle
PUSH EBX,[EBP+8h] ;EBP+8h=hwnd
CALL EndPaint
XOR EAX,EAX
RET
;
;********** this is a general window procedure which in an ordinary
;********** program deals with all messages sent to the window
GENERAL_WNDPROC: ;eax can be used to convey information to the call
PUSH EBP ;use ebp to avoid using eax which may hold information
MOV EBP,[ESP+10h] ;uMsg
MOV ECX,[EDX] ;get number of messages to do
ADD EDX,4 ;jump over size dword
L2:
DEC ECX
JS >L3
CMP [EDX+ECX*8],EBP ;see if its the correct message
JNZ L2 ;no
MOV EBP,ESP
PUSH ESP,EBX,EDI,ESI ;save registers as required by Windows
ADD EBP,4 ;allow for the extra call to here
;now [EBP+8]=hwnd, [EBP+0Ch]=uMsg, [EBP+10h]=wParam, [EBP+14h]=lParam,
CALL [EDX+ECX*8+4] ;call the correct procedure for the message
POP ESI,EDI,EBX,ESP
JNC >L4 ;nc=return value in eax - don't call DefWindowProc
L3:
PUSH [ESP+18h],[ESP+18h],[ESP+18h],[ESP+18h] ;allowing for change of ESP
CALL DefWindowProcA
L4:
POP EBP
RET
;
;******************* This is the actual window procedure
WndProcTable:
MOV EDX,ADDR MESSAGES ;give edx the list of messages to deal with
CALL GENERAL_WNDPROC ;call the generic message handler
RET 10h ;restore the stack as required by caller
;
;*******************************************************************
START:
PUSH 0
CALL GetModuleHandleA ;get handle to the process
MOV [hInst],EAX ;record it in data label hInst
CALL INITIALISE_WNDCLASS ;get ready to register window class
;********** now add things specific to the window to be made
MOV D[EBX],1h+2h+40h ;CS_VREDRAW+CS_HREDRAW+CS_CLASSDC (window class style)
MOV D[EBX+4],ADDR WndProcTable ;window procedure
MOV D[EBX+24h],ADDR WINDOW_CLASSNAME ;window class name
PUSH EBX ;address of structure with window class data
CALL RegisterClassA ;register the window class
PUSH 0,[hInst],0,0 ;owner=desktop
PUSH 200D ;height
PUSH 320D ;width
PUSH 50D,50D ;position y then x
PUSH 90000000h +0C00000h+40000h +80000h +20000h +10000h ;window style
;(POPUP+VISIBLE)+CAPTION+SIZEBOX+SYSMENU+MINIMIZEBOX+MAXIMIZEBOX
PUSH 'Hello World window made by GoAsm' ;window title
PUSH ADDR WINDOW_CLASSNAME ;window class name
PUSH 0 ;extended window style
CALL CreateWindowExA ;make window, returning handle in EAX
;************************ now enter the main message loop
L1:
PUSH 0,0,0
PUSH ADDR MSG
CALL GetMessageA ;wait for message from Windows
OR EAX,EAX ;see if it is WM_QUIT
JZ >L2 ;yes
PUSH ADDR MSG
CALL TranslateMessage ;no so convert message to character if necessary
PUSH ADDR MSG
CALL DispatchMessageA ;and send the message to the window procedure
JMP L1 ;after message dealt with, loop back for next one
L2:
PUSH [hInst],ADDR WINDOW_CLASSNAME ;message was WM_QUIT
CALL UnregisterClassA ;ensure class is removed
PUSH [MSG+8h] ;exit code (send contents of wParam)
CALL ExitProcess ;return to Windows in the manner it prefers