;------------------------------------------------------------------
;
;      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