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

;###########################################################################
;###########################################################################
; LOCAL MACROS
;###########################################################################
;###########################################################################

	;========================================
	; This macro creates a local string
	;========================================
	szText MACRO Name, Text:VARARG
		LOCAL lbl
		JMP lbl
		Name DB Text,0
		lbl:
	ENDM

	;========================================
	; This macro swaps the values of two
	; variables by using the stack
	;========================================
	m2m MACRO M1, M2
		PUSH		M2
		POP		M1
	ENDM

	;========================================
	; Places the return value into eax
	; and then returns from the procedure
	;========================================
	return MACRO arg
		MOV	EAX, arg
        	RET
	ENDM

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

;#################################################################################
;#################################################################################
; 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
    
	;==============================
	;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,"MS Sans Serif">

		; 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
	;==================================
	INVOKE WinMain,hInst,NULL,CommandLine,SW_SHOWDEFAULT

	;==================================
	; Leave the program
	;==================================
	INVOKE ExitProcess,EAX

;########################################################################
; WinMain Function
;########################################################################
WinMain PROC	hInstance	:DWORD,
		hPrevInst	:DWORD,
		CmdLine		:DWORD,
		CmdShow		:DWORD

	;====================
	; Put LOCALs on stack
	;====================
	LOCAL wc		:WNDCLASS
	LOCAL Wwd  		:DWORD
	LOCAL Wht  		:DWORD
	LOCAL 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,
			ADDR szClassName,
                        ADDR 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
	;=================================
	INVOKE PushButton,ADDR NOFLICK_Cap,hMainWnd,12,102,160,33,ID_NOFLICKER
	INVOKE SendMessage,EAX,WM_SETFONT,hFont,0
	INVOKE PushButton,ADDR FLICK_Cap,hMainWnd,248,102,160,33,ID_FLICKER
	INVOKE SendMessage,EAX,WM_SETFONT,hFont,0
	INVOKE PushButton,ADDR ABOUT_Cap,hMainWnd,12,256,160,33,ID_ABOUT
	INVOKE SendMessage,EAX,WM_SETFONT,hFont,0
	INVOKE PushButton,ADDR 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
	INVOKE 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)
		INVOKE	TranslateMessage, ADDR msg
		INVOKE	DispatchMessage, ADDR msg
	.ENDW

	;===========================
	; Delete the font object
	;===========================
	INVOKE DeleteObject, hFont

	;===========================
	; We are through 
	;===========================
	return msg.wParam

WinMain endp
;########################################################################
; End of WinMain Procedure
;########################################################################

;########################################################################
; Main Window Callback Procedure -- WndProc
;########################################################################
WndProc PROC	hWin   :DWORD,
		uMsg   :DWORD,
		wParam :DWORD,
		lParam :DWORD

;========================================
; LOCAL VARIABLES
;=========================================
LOCAL	Pt		:POINT
LOCAL	PS		:PAINTSTRUCT
LOCAL	LastX		:DWORD
LOCAL	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
		;====================================
		INVOKE ManageUpdate, FALSE

	.ELSEIF wParam == ID_NOFLICKER
		;====================================
		; Code to update the window with the
		; backbuffer method to elimiante the
		; flicker on the screen
		;====================================
		INVOKE ManageUpdate, TRUE
		
	.ELSEIF wParam == ID_ABOUT
		;====================================
		; Code to display the about dialog
		;====================================
 		INVOKE DialogBoxParam, hInst, IDD_ABOUT, hMainWnd, ADDR 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
	;===========================
	INVOKE PaintScreen, TRUE

.ELSEIF uMsg == WM_PAINT 
	;=====================================
	; Let windows know we took care of it
	;=====================================
	INVOKE BeginPaint, hMainWnd, ADDR PS
	INVOKE EndPaint, hMainWnd, ADDR PS
	INVOKE 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

WndProc endp
;########################################################################
; End of Main Windows Callback Procedure
;########################################################################

;########################################################################
; ManageUpdate Function
;########################################################################
ManageUpdate PROC	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
			;=================================
			INVOKE PaintScreen, TRUE
		.ELSE
			;=================================
			; NO use the flickering method
			;=================================
			INVOKE PaintScreen, FALSE

		.ENDIF

	.ENDW

done:
	;==================
	; Return good
	;==================
	return TRUE

err:
	;==================
	; Return an error
	;==================
	return FALSE	
         
ManageUpdate endp
;########################################################################
; END of ManageUpdate
;########################################################################

;########################################################################
; PaintScreen Function
;########################################################################
PaintScreen PROC	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
	LOCAL	hMemDC		:DWORD
	LOCAL	ScreenRect	:RECT
	LOCAL	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
		;====================================
		INVOKE 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
		;====================================
		INVOKE DrawWindow, hDC

	.ENDIF

	;================================
	; release the device context
	;================================
	INVOKE ReleaseDC, hMainWnd, hDC

done:
	;==================
	; Return good
	;==================
	return TRUE

err:
	;==================
	; Return an error
	;==================
	return FALSE	
         
PaintScreen endp
;########################################################################
; END of PaintScreen				    
;########################################################################

;########################################################################
; DrawWindow Function
;########################################################################
DrawWindow PROC	DC:DWORD
	
	;============================================
	; This code performs all of the actal drawing
	; for the window
	;============================================

	;===============================
	; Local Variables
	;===============================
	LOCAL	hPen		:DWORD
	LOCAL	hBrush		:DWORD
	LOCAL	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, ADDR Rect_FLICK, DFC_BUTTON, DFCS_BUTTONPUSH
	INVOKE DrawFrameControl, DC, ADDR Rect_NOFLICK, DFC_BUTTON, DFCS_BUTTONPUSH
	INVOKE DrawFrameControl, DC, ADDR Rect_ABOUT, DFC_BUTTON, DFCS_BUTTONPUSH
	INVOKE DrawFrameControl, DC, ADDR 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, ADDR 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, ADDR 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, ADDR FLICK_Cap, (SIZEOF FLICK_Cap)-1, ADDR Rect_FLICK, \
		DT_CENTER OR DT_SINGLELINE OR DT_VCENTER
	INVOKE DrawText, DC, ADDR NOFLICK_Cap, (SIZEOF NOFLICK_Cap)-1, ADDR Rect_NOFLICK, \
		DT_CENTER OR DT_SINGLELINE OR DT_VCENTER
	INVOKE DrawText, DC, ADDR ABOUT_Cap, (SIZEOF ABOUT_Cap)-1, ADDR Rect_ABOUT, \
		DT_CENTER OR DT_SINGLELINE OR DT_VCENTER
	INVOKE DrawText, DC, ADDR EXIT_Cap, (SIZEOF EXIT_Cap)-1, ADDR 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	
         
DrawWindow endp
;########################################################################
; END of DrawWindow				    
;########################################################################

;########################################################################
; Handle the About Dialog Box
;########################################################################
AboutProc PROC	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
		;=============================
		INVOKE 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

AboutProc endp
;########################################################################
; END AboutProc
;########################################################################

;########################################################################
; Misc Center Window from SIB by Steve Gibson. Thanks Steve!
;########################################################################
MiscCenterWnd PROC	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

MiscCenterWnd	ENDP
;########################################################################
; END MISC CENTER WINDOW
;########################################################################

;########################################################################
; PUSHBUTTON PROCEDURE
;########################################################################
PushButton PROC 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,
            ADDR btnClass,lpText,
            WS_CHILD OR WS_VISIBLE,
            a,b,wd,ht,hParent,ID,
            hInst,NULL

    RET

PushButton endp
;########################################################################
; END of PUSHBUTTON PROCEDURE
;########################################################################

;######################################
; THIS IS THE END OF THE PROGRAM CODE #
;######################################
END start