;===================================================================
;              ESF DEMO - Eliminating Screen Flicker                 
;===================================================================
;===================================================================
;                     ABOUT THIS DEMO PROGRAM                        
;===================================================================
;
;       This demo program is part of a tutorial on eliminating the
;       screen flicker that is typically found in an application. 
;
;       The tutorial contains first, an HTML document describing the 
;       methods we will use to eliminate the flicker, and detailing 
;       step-by-step how to achive this. Second, is the demo program
;       that allows you to compare the two methods. Finally, this
;       document -- the source code -- is included. Although I have
;       many snippets of code in the HTML document, I wanted you
;       to be able to see for yourself the entire picture. You
;       may use whatever code you would like in your own programs,
;       or, if you prefer, just use this as a guide for your own
;       applications. The source code is in HTML format so it can be
;       viewed anywhere on anything that has a browser. Just copy 
;       and paste what you need.
;
;       With that stated a few notes about the source code for this
;       application are in order...
;
;               1 -- I have used the same routine to paint the 
;                   screen for both the flicker and non-flicker
;                   versions. I pass in a TRUE/FALSE value that
;                   says use, or don't use, a backbuffer.
;
;               2 -- My coding convention for the WM_PAINT procedure
;                   is a little different than most peoples. First, 
;                   I do not bother with only updating the invalid
;                   portions, I update the entire screen. Second, I
;                   choose to paint my own controls if I have enough
;                   stuff to draw that warrants using a backbuffer.
;                   Finally, I like to do everything in it's own
;                   routine instead of in the normal WM_PAINT 
;                   message.
;
;               3 -- This code is heavily commented, as are all of 
;                   my applications. So, you should not have any 
;                   trouble with this code. But, if you do, please
;                   feel free to contact me:
;                            Http://www.fastsoftware.com
;                              chobbs@fastsoftware.com 
;
;               4 -- Finally, I use a back buffer to do the normal
;                   screen updates for this application. The only
;                   time the flickering update is used is when the
;                   user clicks the "Update w/ Flicker" button.
;
;===================================================================
;===================================================================

;###########################################################################
;###########################################################################
; THE COMPILER OPTIONS
;###########################################################################
;###########################################################################

;        .386
;        .MODEL flat, stdcall
;        OPTION CASEMAP :none   ; case sensitive

;###########################################################################
;###########################################################################
; THE INCLUDES SECTION
;###########################################################################
;###########################################################################

;        INCLUDE \masm32\include\windows.inc
;        INCLUDE \masm32\include\comctl32.inc
;        INCLUDE \masm32\include\comdlg32.inc
;        INCLUDE \masm32\include\shell32.inc
;        INCLUDE \masm32\include\user32.inc
;        INCLUDE \masm32\include\kernel32.inc
;        INCLUDE \masm32\include\gdi32.inc
	
;        INCLUDELIB \masm32\lib\comctl32.lib
;        INCLUDELIB \masm32\lib\comdlg32.lib
;        INCLUDELIB \masm32\lib\shell32.lib
;        INCLUDELIB \masm32\lib\gdi32.lib
;        INCLUDELIB \masm32\lib\user32.lib
;        INCLUDELIB \masm32\lib\kernel32.lib

;:::::::: ADDED :::::::::
include 'win32axp.inc'
include 'macro\if.inc'
INVOKE	fix invoke
OFFSET	fix
.IF	fix .if
.ELSE	fix .else
.ELSEIF fix .elseif
.ENDIF	fix .endif
.WHILE	fix .while
.ENDW	fix .endw

struc DB [chars]{
common
  . db chars
  sizeof.#. = $ - .
}
;::::::::::::::::::::::::

;###########################################################################
;###########################################################################
; LOCAL MACROS
;###########################################################################
;###########################################################################

	;========================================
	; This macro creates a local string
	;========================================
;        szText MACRO Name, Text:VARARG
;                LOCAL lbl
;                JMP lbl
;                Name DB Text,0
;                lbl:
;        ENDM
	macro szText Name, [Text]{
	common
	local lbl
	  jmp	  lbl
	  Name	  db Text, 0
	  lbl:
	}

	;========================================
	; This macro swaps the values of two
	; variables by using the stack
	;========================================
;        m2m MACRO M1, M2
;                PUSH            M2
;                POP             M1
;        ENDM
	macro m2m M1, M2{
	  push	  M2
	  pop	  M1
	}

	;========================================
	; Places the return value into eax
	; and then returns from the procedure
	;========================================
	;return MACRO arg
	;        MOV     EAX, arg
	;        RET
	;ENDM
	macro return arg{
	  mov	  eax, arg
	  ret
	}

	;========================================
	; This macro creates an RGB triplet from
	; the threee specified colors
	;========================================
;        RGB MACRO red, green, blue
;                XOR     EAX,EAX
;                MOV     AH,blue
;                SHL     EAX,8
;                MOV     AH,green
;                MOV     AL,red
;        ENDM
	macro RGB red, green, blue{
	  xor	  eax, eax
	  mov	  ah, blue
	  shl	  eax, 8
	  mov	  ah, green
	  mov	  al, red
	}

;#################################################################################
;#################################################################################
; THE PROTOTYPES
;#################################################################################
;#################################################################################

	;==================================
	; Main Program Procedures
	;==================================
;        WinMain PROTO           :DWORD,:DWORD,:DWORD,:DWORD
;        WndProc PROTO           :DWORD,:DWORD,:DWORD,:DWORD

	;====================================
	; The Update Manager
	;====================================
;        ManageUpdate PROTO      :BYTE

	;====================================
	; Drawing Procedures
	;====================================
;        PaintScreen PROTO       :BYTE
;        DrawWindow PROTO        :DWORD

	;====================================
	; MISC Procedures
	;====================================
;        AboutProc PROTO         :DWORD,:DWORD,:DWORD,:DWORD
;        MiscCenterWnd PROTO     :DWORD,:DWORD
;        PushButton PROTO        :DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD

;#################################################################################
;#################################################################################
; BEGIN INITIALIZED DATA
;#################################################################################
;#################################################################################

;    .DATA
     .data
    
	;==============================
	;Text for the Window Title
	;==============================
	szDisplayName	DB "Eliminating Screen Flicker by Lightning Software",0
      
	;==============================
	;Windows handles and Misc
	;==============================
	msg  MSG	?     ; For message handling
	CommandLine	DD 0	; for the commandline params
	hMainWnd	DD 0	; Handle to the main window
	hInst		DD 0	; Handle to an Instance

	;========================================================
	; This is the buffer for wvsprintfA it can hold up to
	; 40 characters inlcuding the NULL
	;========================================================
	szBuffer	DB 40 dup (0)

	;========================================================
	; This is used to pass arguments to wvsprintfA it can 
	; hold up to 4 different args
	;========================================================
	dwArgs		DD 4 dup (0)

	;===============================================
	; Current Screen Update Number
	;===============================================
	CurUpdate	DD 0

	;===========================================
	; These are the rects fro the placement
	; of text and colors on the window
	;===========================================
	Rect_DEMO	RECT	1,1,419,94	      ; Left, top, right, bottom
	Rect_HOWTO	RECT	1,142,419,208	      ; Left, top, right, bottom
	Rect_CURNUM	RECT	1,207,419,249	      ; Left, top, right, bottom
	Rect_RED1	RECT	184,93,235,144	      ; Left, top, right, bottom
	Rect_RED2	RECT	184,248,235,299       ; Left, top, right, bottom

	;===========================================
	; These are the rects fro the placement
	; of the buttons in the window
	;===========================================
	Rect_NOFLICK	RECT	12,102,172,135	      ; Left, top, right, bottom
	Rect_FLICK	RECT	248,102,408,135       ; Left, top, right, bottom
	Rect_ABOUT	RECT	12,256,172,289	      ; Left, top, right, bottom
	Rect_EXIT	RECT	248,256,408,289       ; Left, top, right, bottom
	
	;===============================
	; Strings for the application
	;===============================
	szClassName	DB "ESF_Class",0
	szNoHomePage	DB "Unable to open www.fastsoftware.com!",0
	szHomepage	DB "Http://www.fastsoftware.com/",0
	szCurNumber	DB "Current Update Number: %d",0
	szDemo		DB "A simple demo showing screen updates with ",\
			   "flicker and screen updates without the flicker!",0
	szHowTo 	DB "Click on one of the two update buttons above to see ",\
			   "the screen updated 500 times. One performs this update ",\
			   "with normal methods, the other uses the flicker-less method.",0

	;===============================
	; Captions for the buttons
	;===============================
	NOFLICK_Cap	DB "Update w/o Flicker",0
	FLICK_Cap	DB "Update w/ Flicker",0
	ABOUT_Cap	DB "About this Demo",0
	EXIT_Cap	DB "Exit this Demo",0

	;=====================================================
	;Initialize the Font structure for generic app then
	; change what is necessary before calls
	;=====================================================

	Font	LOGFONT 11,0,0,0,FW_NORMAL,\
			0,0,0,ANSI_CHARSET,OUT_STRING_PRECIS,\
			CLIP_STROKE_PRECIS,DEFAULT_QUALITY,\
			DEFAULT_PITCH OR FF_DONTCARE,0

	;:::::::: ADDED :::::::::
	store qword "MS Sans " at Font.lfFaceName+8
	store qword "Serif"    at Font.lfFaceName+8
	;::::::::::::::::::::::::
		; Height Values for the font
			; 11 = size 8
			; 13 = size 10
			; -16 = size 12
			; -19 = size 14
			; 24 = size 18
			; -32 = size 24

;#################################################################################
;#################################################################################
; BEGIN EQUATES
;#################################################################################
;#################################################################################

	;=================
	;Utility Equates
	;=================
FALSE		EQU	0
TRUE		EQU	1

	;================
	; Button ID's
	;================
ID_FLICKER	EQU	850	; Updatye with flicker
ID_NOFLICKER	EQU	875	; Update without flicker
ID_ABOUT	EQU	885	; The about app button
ID_EXIT 	EQU	895	; The exit button

	;================
	; resource IDs
	;================
IDI_ICON	EQU	01h		
IDD_ABOUT	EQU	04h

;#################################################################################
;#################################################################################
; BEGIN THE CODE SECTION
;#################################################################################
;#################################################################################

  .code

start:
	;==================================
	; Obtain the instance for the
	; application
	;==================================
	INVOKE GetModuleHandle, NULL
	MOV	[hInst], EAX

	;==================================
	; Is there a commandline to parse?
	;==================================
	INVOKE GetCommandLine
	MOV    [CommandLine], EAX

	;==================================
	; Call the WinMain procedure
	;==================================
	stdcall WinMain,[hInst],NULL,[CommandLine],SW_SHOWDEFAULT

	;==================================
	; Leave the program
	;==================================
	INVOKE ExitProcess,EAX

;########################################################################
; WinMain Function
;########################################################################
proc WinMain	hInstance	:DWORD,\
		hPrevInst	:DWORD,\
		CmdLine 	:DWORD,\
		CmdShow 	:DWORD

	;====================
	; Put LOCALs on stack
	;====================
	local wc		:WNDCLASS,\
	      Wwd		:DWORD,\
	      Wht		:DWORD,\
	      hFont		:DWORD

	;==================================================
	; Fill WNDCLASS structure with required variables
	;==================================================
	MOV	[wc.style],CS_HREDRAW OR CS_VREDRAW \
			   OR CS_BYTEALIGNWINDOW
	MOV	[wc.lpfnWndProc],OFFSET WndProc
	MOV	[wc.cbClsExtra],NULL
	MOV	[wc.cbWndExtra],NULL
	m2m	[wc.hInstance],[hInst]	 ;<< NOTE: macro not mnemonic
	MOV	[wc.hbrBackground],COLOR_WINDOW
	MOV	[wc.lpszMenuName],NULL
	MOV	[wc.lpszClassName],OFFSET szClassName
	INVOKE LoadIcon, [hInst], IDI_ICON ; icon ID
	MOV	[wc.hIcon],EAX
	INVOKE LoadCursor,NULL,IDC_ARROW
	MOV	[wc.hCursor],EAX

	;================================
	; Register our class we created
	;================================
	INVOKE RegisterClass, addr wc

	;================================
	; Create window at following size
	;================================
	MOV	[Wwd], 429
	MOV	[Wht], 327
	
	;===========================================
	; Create the main screen
	;===========================================
	INVOKE CreateWindowEx,NULL,\
			szClassName,\
			szDisplayName,\
			WS_OVERLAPPEDWINDOW XOR WS_MAXIMIZEBOX,\
			0,0,[Wwd],[Wht],\
			NULL,NULL,\
			[hInst],NULL
	
	;===========================================
	; Put the window handle in for future uses 
	;===========================================
	MOV	[hMainWnd], EAX

	;==========================================
	; Create the font we want for the buttons
	;==========================================
	MOV	[Font.lfWeight], FW_BOLD
	MOV	[Font.lfHeight], -16
	INVOKE CreateFontIndirect, OFFSET Font
	MOV	[hFont], EAX
	
	;=================================
	; Create our 4 buttons
	;=================================
	stdcall PushButton, NOFLICK_Cap,[hMainWnd],12,102,160,33,ID_NOFLICKER
	INVOKE SendMessage,EAX,WM_SETFONT,[hFont],0
	stdcall PushButton, FLICK_Cap,[hMainWnd],248,102,160,33,ID_FLICKER
	INVOKE SendMessage,EAX,WM_SETFONT,[hFont],0
	stdcall PushButton, ABOUT_Cap,[hMainWnd],12,256,160,33,ID_ABOUT
	INVOKE SendMessage,EAX,WM_SETFONT,[hFont],0
	stdcall PushButton, EXIT_Cap,[hMainWnd],248,256,160,33,ID_EXIT
	INVOKE SendMessage,EAX,WM_SETFONT,[hFont],0

	;========================================
	; Set the current Update number to zero
	;========================================
	MOV	[CurUpdate], 0

	;================================
	; Center the window 
	;================================
	INVOKE GetDesktopWindow
	stdcall MiscCenterWnd, [hMainWnd], EAX

	;================================
	; Show the window
	;================================
	INVOKE ShowWindow,[hMainWnd],SW_SHOWNORMAL

	;===================================
	; Loop until PostQuitMessage is sent
	;===================================
	.WHILE TRUE
		INVOKE	GetMessage, addr msg, NULL, 0, 0
		;.BREAK .IF (!eax)
		test	eax, eax
		jz	.exit_while_loop
		INVOKE	TranslateMessage, addr msg
		INVOKE	DispatchMessage, addr msg
	.ENDW
	.exit_while_loop:

	;===========================
	; Delete the font object
	;===========================
	INVOKE DeleteObject, [hFont]

	;===========================
	; We are through 
	;===========================

	return [msg.wParam]

endp
;########################################################################
; End of WinMain Procedure
;########################################################################

;########################################################################
; Main Window Callback Procedure -- WndProc
;########################################################################
proc WndProc	hWin   :DWORD,\
		uMsg   :DWORD,\
		wParam :DWORD,\
		lParam :DWORD

;========================================
; LOCAL VARIABLES
;=========================================
local	Pt		:POINT,\
	PS		:PAINTSTRUCT,\
	LastX		:DWORD,\
	LastY		:DWORD

.IF [uMsg] = WM_COMMAND

;========== COMMAND BUTTONS =========================================================
	.IF [wParam] = ID_FLICKER
		;====================================
		; Code to update the display with the
		; normal method of drawing right on
		; the main window
		;====================================
		stdcall ManageUpdate, FALSE

	.ELSEIF [wParam] = ID_NOFLICKER
		;====================================
		; Code to update the window with the
		; backbuffer method to elimiante the
		; flicker on the screen
		;====================================
		stdcall ManageUpdate, TRUE
		
	.ELSEIF [wParam] = ID_ABOUT
		;====================================
		; Code to display the about dialog
		;====================================
		INVOKE DialogBoxParam, [hInst], IDD_ABOUT, [hMainWnd], AboutProc, NULL


	.ELSEIF [wParam] = ID_EXIT
		;====================================
		; Code to quit this demo
		;====================================
		INVOKE SendMessage,[hWin],WM_SYSCOMMAND,SC_CLOSE,NULL

	.ENDIF

;======================== Command Buttons =============================
 
.ELSEIF [uMsg] = WM_ERASEBKGND
	;===========================
	; Say we handled it
	;===========================
	return 1

.ELSEIF [uMsg] = WM_ACTIVATE
	;===========================
	; Call to Paint the screen
	;===========================
	stdcall PaintScreen, TRUE

.ELSEIF [uMsg] = WM_PAINT
	;=====================================
	; Let windows know we took care of it
	;=====================================
	INVOKE BeginPaint, [hMainWnd], addr PS
	INVOKE EndPaint, [hMainWnd], addr PS
	stdcall PaintScreen, TRUE

	;====================================
	; Return just to make sure 
	;====================================
	return 1

.ELSEIF [uMsg] = WM_DESTROY
	;===========================
	; Kill the application
	;===========================
	INVOKE PostQuitMessage,NULL
	return 0 
 
.ENDIF

;=================================================
; Let the default procedure handle the message
;=================================================

INVOKE DefWindowProc,[hWin],[uMsg],[wParam],[lParam]

ret

endp
;########################################################################
; End of Main Windows Callback Procedure
;########################################################################

;########################################################################
; ManageUpdate Function
;########################################################################
proc ManageUpdate	UseBackBuffer:BYTE
	
	;============================================
	; This will update our display 500 times
	; with either the flicker or the no-flicker
	; method of updating
	;============================================


	;================================
	; Make sure the count is at zero
	;================================
	MOV	[CurUpdate], 0

	;========================================
	; Loop through 500 times and call the
	; PaintScreen procedure each time through
	;========================================
	.WHILE [CurUpdate] < 500
		;======================
		; Increment the count
		;======================
		INC [CurUpdate]

		;=============================
		; Make the proper call based
		; on whether or not they want
		; to use the backbuffer
		;=============================
		.IF [UseBackBuffer] = TRUE
			;=================================
			; Yes use the flicker free method
			;=================================
			stdcall PaintScreen, TRUE
		.ELSE
			;=================================
			; NO use the flickering method
			;=================================
			stdcall PaintScreen, FALSE

		.ENDIF

	.ENDW

.done:
	;==================
	; Return good
	;==================
	return TRUE

.err:
	;==================
	; Return an error
	;==================
	return FALSE	
	 
endp
;########################################################################
; END of ManageUpdate
;########################################################################

;########################################################################
; PaintScreen Function
;########################################################################
proc PaintScreen	UseBackBuffer:BYTE
	
	;============================================
	; Code to update the display. It is called
	; whenever the screen needs painting it takes
	; as its only parameter whether or not to 
	; draw with a backbuffer. This code calls the
	; DrawWindow Proc to do the actaul drawing.
	;============================================

	;============================
	; LOCAL VARIABLES
	;============================
	local	hDC		:DWORD,\
		hMemDC		:DWORD,\
		ScreenRect	:RECT,\
		hBitmap 	:DWORD

	;=================================
	; Get the client rectangle
	;=================================
	INVOKE GetClientRect, [hMainWnd], addr ScreenRect

	;============================
	; get the DC
	;============================
	INVOKE GetDC, [hMainWnd]
	MOV	[hDC], EAX

	;=========================================
	; Did they want to use a backbuffer
	;=========================================
	.IF [UseBackBuffer] = TRUE
		;=========================================
		; Yes they want to update without flicker
		;=========================================
	
		;============================
		; Create a compatible DC
		;============================
		INVOKE CreateCompatibleDC, [hDC]
		MOV	[hMemDC], EAX
	
		;==============================
		; Now create a Bitmap for that
		; offscreen DC
		;==============================
		MOV	EAX, [ScreenRect.right]
		SUB	EAX, [ScreenRect.left]
		MOV	EBX, [ScreenRect.bottom]
		SUB	EBX, [ScreenRect.top]
		INVOKE CreateCompatibleBitmap, [hDC], EAX, EBX
		MOV	[hBitmap], EAX
		
		;=============================
		; Select that bitmap into the
		; object, preserve old
		;=============================
		INVOKE SelectObject, [hMemDC], [hBitmap]
		PUSH	EAX

		;=============================
		; Erase the Background
		;=============================
		INVOKE GetSysColor, COLOR_WINDOW
		INVOKE CreateSolidBrush, EAX
		PUSH	EAX
		INVOKE FillRect, [hMemDC], addr ScreenRect, EAX
		POP	EAX
		INVOKE DeleteObject,EAX

		;====================================
		; Draw the stuff onto the backbuffer
		;====================================
		stdcall DrawWindow, [hMemDC]

		;===========================
		; Copy buffer to actual
		;===========================
		MOV	EAX, [ScreenRect.right]
		SUB	EAX, [ScreenRect.left]
		MOV	EBX, [ScreenRect.bottom]
		SUB	EBX, [ScreenRect.top]
		INVOKE BitBlt,[hDC], [ScreenRect.left], [ScreenRect.top], EAX, EBX,\
				[hMemDC], 0, 0, SRCCOPY

		;============================
		; Select old int hMemDC
		;============================
		POP	EAX
		INVOKE SelectObject, [hMemDC], EAX

		;============================
		; Delete the Compatible DC
		;============================
		INVOKE DeleteDC, [hMemDC]

		;===============================
		; Delete the Compatible Bitmap
		;===============================
		INVOKE DeleteObject, [hBitmap]

	.ELSE
		;=============================
		; No so just update with the
		; normal method of drawing on
		; the main window DC
		;=============================

		;=============================
		; Erase the Background
		;=============================
		INVOKE GetSysColor, COLOR_WINDOW
		INVOKE CreateSolidBrush, EAX
		PUSH	EAX
		INVOKE FillRect, [hDC], addr ScreenRect, EAX
		POP	EAX
		INVOKE DeleteObject,EAX

		;====================================
		; Draw the stuff onto the backbuffer
		;====================================
		stdcall DrawWindow, [hDC]

	.ENDIF

	;================================
	; release the device context
	;================================
	INVOKE ReleaseDC, [hMainWnd], [hDC]

.done:
	;==================
	; Return good
	;==================
	return TRUE

.err:
	;==================
	; Return an error
	;==================
	return FALSE	
	 
endp
;########################################################################
; END of PaintScreen                                
;########################################################################

;########################################################################
; DrawWindow Function
;########################################################################
proc DrawWindow DC:DWORD
	
	;============================================
	; This code performs all of the actal drawing
	; for the window
	;============================================

	;===============================
	; Local Variables
	;===============================
	local	hPen		:DWORD,\
		hBrush		:DWORD,\
		hFont		:DWORD

;===============================================
; START OUT BY DRAWING THE OUTLINES
;===============================================
	;========================================
	; Create our new pen of the color black
	;========================================
	INVOKE CreatePen, PS_SOLID, 3, 0
	MOV	[hPen], EAX

	;========================================
	; Select our new pen and save the old one
	; on the stack for later
	;========================================
	INVOKE SelectObject, [DC], [hPen]
	PUSH	EAX

	;======================================
	; Draw the outlining frame for form
	; and the dividers for the palette
	;======================================
	INVOKE MoveToEx, [DC], 1, 1, NULL
	INVOKE LineTo, [DC], 418, 1
	INVOKE LineTo, [DC], 418, 298
	INVOKE LineTo, [DC], 1, 298
	INVOKE LineTo, [DC], 1, 1

;===============================================
; Now draw the seperating boxes
;===============================================
	;==================================
	; Make the call to create a
	; red brush for the two red boxes
	;==================================
	RGB	255,0,0
	INVOKE CreateSolidBrush, EAX
	PUSH	EAX

	;===============================
	; Select the brush into our DC
	; and preserve the old object
	;===============================
	INVOKE SelectObject, [DC], EAX
	PUSH	EAX

	;======================================
	; Make a call to draw the rectangle
	; outlined in the pen color and filled
	; in with the brush color
	;======================================
	INVOKE Rectangle, [DC], [Rect_RED1.left], [Rect_RED1.top],\
			[Rect_RED1.right], [Rect_RED1.bottom]
	INVOKE Rectangle, [DC], [Rect_RED2.left], [Rect_RED2.top],\
			[Rect_RED2.right], [Rect_RED2.bottom]

	;===============================
	; Select the old object back in
	;===============================
	POP	EAX
	INVOKE SelectObject, [DC], EAX
		
	;===============================
	; Delete our brush we created
	;===============================
	POP	EAX
	INVOKE DeleteObject, EAX

	;==================================
	; Make the call to create a
	; green brush for the demo box
	;==================================
	RGB	0,192,0
	INVOKE CreateSolidBrush, EAX
	PUSH	EAX

	;===============================
	; Select the brush into our DC
	; and preserve the old object
	;===============================
	INVOKE SelectObject, [DC], EAX
	PUSH	EAX

	;======================================
	; Make a call to draw the rectangle
	; outlined in the pen color and filled
	; in with the brush color
	;======================================
	INVOKE Rectangle, [DC], [Rect_DEMO.left], [Rect_DEMO.top],\
			[Rect_DEMO.right], [Rect_DEMO.bottom]

	;===============================
	; Select the old object back in
	;===============================
	POP	EAX
	INVOKE SelectObject, [DC], EAX
		
	;===============================
	; Delete our brush we created
	;===============================
	POP	EAX
	INVOKE DeleteObject, EAX

	;==================================
	; Make the call to create a blue
	; highlight brush for the demo box
	;==================================
	INVOKE GetSysColor, COLOR_HIGHLIGHT
	INVOKE CreateSolidBrush, EAX
	PUSH	EAX

	;===============================
	; Select the brush into our DC
	; and preserve the old object
	;===============================
	INVOKE SelectObject, [DC], EAX
	PUSH	EAX

	;======================================
	; Make a call to draw the rectangle
	; outlined in the pen color and filled
	; in with the brush color
	;======================================
	INVOKE Rectangle, [DC], [Rect_HOWTO.left], [Rect_HOWTO.top],\
			[Rect_HOWTO.right], [Rect_HOWTO.bottom]

	;===============================
	; Select the old object back in
	;===============================
	POP	EAX
	INVOKE SelectObject, [DC], EAX
		
	;===============================
	; Delete our brush we created
	;===============================
	POP	EAX
	INVOKE DeleteObject, EAX

	;==================================
	; Make the call to create a blue
	; highlight brush for the demo box
	;==================================
	RGB	255,255,0
	INVOKE CreateSolidBrush, EAX
	PUSH	EAX

	;===============================
	; Select the brush into our DC
	; and preserve the old object
	;===============================
	INVOKE SelectObject, [DC], EAX
	PUSH	EAX

	;======================================
	; Make a call to draw the rectangle
	; outlined in the pen color and filled
	; in with the brush color
	;======================================
	INVOKE Rectangle, [DC], [Rect_CURNUM.left], [Rect_CURNUM.top],\
			[Rect_CURNUM.right], [Rect_CURNUM.bottom]

	;===============================
	; Select the old object back in
	;===============================
	POP	EAX
	INVOKE SelectObject, [DC], EAX
		
	;===============================
	; Delete our brush we created
	;===============================
	POP	EAX
	INVOKE DeleteObject, EAX

	;====================================
	; Select the old object back in
	;====================================
	POP	EAX
	INVOKE SelectObject, [DC], EAX
	
	;==================================
	; Delete our Pen we created
	;==================================
	INVOKE DeleteObject, [hPen]

;===============================================
; Now draw the buttons onto the DC
;===============================================
	INVOKE DrawFrameControl, [DC], Rect_FLICK, DFC_BUTTON, DFCS_BUTTONPUSH
	INVOKE DrawFrameControl, [DC], Rect_NOFLICK, DFC_BUTTON, DFCS_BUTTONPUSH
	INVOKE DrawFrameControl, [DC], Rect_ABOUT, DFC_BUTTON, DFCS_BUTTONPUSH
	INVOKE DrawFrameControl, [DC], Rect_EXIT, DFC_BUTTON, DFCS_BUTTONPUSH

;===============================================
; Now text into the boxes we created
;===============================================
	;============================
	; Set text and bkgnd mode
	;============================
	INVOKE SetTextColor, [DC], 00000000h
	INVOKE SetBkMode, [DC], TRANSPARENT

	;=================================================
	; Create and Select the Font preserve old on stack
	;=================================================
	MOV	[Font.lfWeight], FW_BOLD
	MOV	[Font.lfHeight], -24
	INVOKE CreateFontIndirect, OFFSET Font
	MOV	[hFont], EAX
	INVOKE SelectObject, [DC], [hFont]
	PUSH	EAX

	;===================================
	; Paint the Demo Text
	;===================================
	INVOKE DrawText, [DC], addr szDemo, (sizeof.szDemo)-1, Rect_DEMO, \
		DT_CENTER OR DT_WORDBREAK

	;===============================
	; Set the text color
	;===============================
	RGB	0,0,192
	INVOKE SetTextColor, [DC], EAX

	;===================================
	; Print out the Cur Update Number 
	;===================================
	MOV	EAX, [CurUpdate]
	MOV	[dwArgs], EAX
	INVOKE wvsprintfA, addr szBuffer, addr szCurNumber, OFFSET dwArgs
	INVOKE DrawText, [DC], addr szBuffer, EAX, Rect_CURNUM,\
		DT_CENTER OR DT_VCENTER OR DT_SINGLELINE

	;===============================
	; Restore old object 
	;===============================
	POP	EAX
	INVOKE SelectObject, [DC], EAX

	;===============================
	; Delete the FONT object
	;===============================
	INVOKE DeleteObject, [hFont]

	;===============================
	; Set text color
	;===============================
	INVOKE SetTextColor, [DC], 0

	;=================================================
	; Create and Select the Font preserve old on stack
	;=================================================
	MOV	[Font.lfHeight], -16
	INVOKE CreateFontIndirect, OFFSET Font
	MOV	[hFont], EAX
	INVOKE SelectObject, [DC], [hFont]
	PUSH	EAX

	;===================================
	; Paint the Text for the buttons
	;===================================
	INVOKE DrawText, [DC], FLICK_Cap, (sizeof.FLICK_Cap)-1, Rect_FLICK, \
		DT_CENTER OR DT_SINGLELINE OR DT_VCENTER
	INVOKE DrawText, [DC], NOFLICK_Cap, (sizeof.NOFLICK_Cap)-1, Rect_NOFLICK, \
		DT_CENTER OR DT_SINGLELINE OR DT_VCENTER
	INVOKE DrawText, [DC], ABOUT_Cap, (sizeof.ABOUT_Cap)-1, Rect_ABOUT, \
		DT_CENTER OR DT_SINGLELINE OR DT_VCENTER
	INVOKE DrawText, [DC], EXIT_Cap, (sizeof.EXIT_Cap)-1, Rect_EXIT, \
		DT_CENTER OR DT_SINGLELINE OR DT_VCENTER

	;===============================
	; Restore old object 
	;===============================
	POP	EAX
	INVOKE SelectObject, [DC], EAX

	;===============================
	; Delete the FONT object
	;===============================
	INVOKE DeleteObject, [hFont]

	;============================
	; Set the text color
	;============================
	RGB	255,255,255
	INVOKE SetTextColor, [DC], EAX

	;=================================================
	; Create and Select the Font preserve old on stack
	;=================================================
	MOV	[Font.lfWeight], FW_NORMAL
	MOV	[Font.lfHeight], -16
	INVOKE CreateFontIndirect, OFFSET Font
	MOV	[hFont], EAX
	INVOKE SelectObject, [DC], [hFont]
	PUSH	EAX

	;===================================
	; Paint the Demo Text
	;===================================
	INVOKE DrawText, [DC], addr szHowTo, (sizeof.szHowTo)-1, addr Rect_HOWTO, \
		DT_CENTER OR DT_WORDBREAK

	;===============================
	; Restore old object 
	;===============================
	POP	EAX
	INVOKE SelectObject, [DC], EAX

	;===============================
	; Delete the FONT object
	;===============================
	INVOKE DeleteObject, [hFont]

.done:
	;==================
	; Return good
	;==================
	return TRUE

.err:
	;==================
	; Return an error
	;==================
	return FALSE	
	 
endp
;########################################################################
; END of DrawWindow                                 
;########################################################################

;########################################################################
; Handle the About Dialog Box
;########################################################################

proc AboutProc	hDlg   :DWORD,\
		uMsg   :DWORD,\
		wParam :DWORD,\
		lParam :DWORD

	;=================================
	; The equate for the homepage code
	;=================================
	IDHOME		EQU	0

	;=========================
	; Get the message into eax
	;=========================
	MOV	EAX, [uMsg]
	.IF (EAX = WM_INITDIALOG)
		;=============================
		; Center the Dialog Box
		;=============================
		stdcall MiscCenterWnd, [hDlg], [hMainWnd]

	.ELSEIF (EAX = WM_COMMAND) & ([wParam] = IDHOME)
		;===================================
		; Execute our homepage
		;===================================
		INVOKE ShellExecute,0,0,addr szHomepage,0,0,0

		.IF EAX <= 32
			;======================
			; Tell them we can't 
			; open the homepage
			;======================
			INVOKE MessageBox, [hMainWnd], OFFSET szNoHomePage, NULL, MB_OK

		.ENDIF
		
	.ELSEIF (EAX = WM_COMMAND) & ([wParam] = IDOK)
		;========================================
		; They are done so End the Dialog Proc 
		;========================================
		INVOKE EndDialog, [hDlg], TRUE

	.ELSE
		;==================================
		; Show that we didn't process
		;==================================
		MOV	EAX, FALSE	
		JMP	.Return

	.ENDIF

	;==================================
	; Show that we did process
	;==================================
	MOV	EAX, TRUE
	
	;==================================
	; Return from this message
	;==================================
	.Return: ret

endp
;########################################################################
; END AboutProc
;########################################################################

;########################################################################
; Misc Center Window from SIB by Steve Gibson. Thanks Steve!
;########################################################################
proc MiscCenterWnd	hChild:DWORD,\
			hParent:DWORD

		; Define the local variables
		local	rcP:RECT, rcC:RECT, xNew:DWORD, yNew:DWORD

INVOKE	GetWindowRect, [hParent], addr rcP

.IF (eax)
	INVOKE	GetWindowRect, [hChild], addr rcC
	.IF (eax)
		MOV	EAX, [rcP.right]  ;center horizontally
		SUB	EAX, [rcP.left]   ;x=Px+(Pdx-Cdx)/2
		SUB	EAX, [rcC.right]
		ADD	EAX, [rcC.left]
		SAR	EAX, 1
		ADD	EAX, [rcP.left]
	
		; check if off screen at left
		.IF (SIGN?)
			MOV	EAX, 0
		.ENDIF
		MOV	[xNew], EAX

		INVOKE	GetSystemMetrics, SM_CXFULLSCREEN
		SUB	EAX, [rcC.right]
		ADD	EAX, [rcC.left]
		
		; check if off screen at right
		.IF (EAX < [xNew])
			MOV	[xNew], EAX
		.ENDIF

		MOV	EAX, [rcP.bottom] ; center vertically
		SUB	EAX, [rcP.top]	  ; y=Py+(Pdy-Cdy)/2
		SUB	EAX, [rcC.bottom]
		ADD	EAX, [rcC.top]
		SAR	EAX, 1
		ADD	EAX, [rcP.top]

		; check if off screen at top
		.IF (SIGN?)
			MOV	EAX, 0
		.ENDIF
		MOV	[yNew],EAX

		INVOKE	GetSystemMetrics, SM_CYFULLSCREEN
		SUB	EAX, [rcC.bottom]
		ADD	EAX, [rcC.top]
		.IF (EAX < [yNew])
			MOV	[yNew], EAX
		.ENDIF

		INVOKE	SetWindowPos, [hChild], NULL, [xNew], [yNew], 0, 0,\
				SWP_NOSIZE + SWP_NOZORDER

	.ENDIF
.ENDIF

.Return: ret

endp
;########################################################################
; END MISC CENTER WINDOW
;########################################################################

;########################################################################
; PUSHBUTTON PROCEDURE
;########################################################################
proc PushButton lpText:DWORD,hParent:DWORD,\
		a:DWORD,b:DWORD,wd:DWORD,ht:DWORD,ID:DWORD

; PushButton PROTO :DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD
; invoke PushButton,ADDR szCaption,hWnd,20,20,100,25,500

    szText btnClass, "BUTTON"

    INVOKE CreateWindowEx,0,\
	    btnClass,[lpText],\
	    WS_CHILD OR WS_VISIBLE,\
	    [a],[b],[wd],[ht],[hParent],[ID],\
	    [hInst],NULL

    ret

endp
;########################################################################
; END of PUSHBUTTON PROCEDURE
;########################################################################

;######################################
; THIS IS THE END OF THE PROGRAM CODE #
;######################################
.end start
