Upcoming Events
Unite 2010
11/10 - 11/12 @ Montréal, Canada

GDC China
12/5 - 12/7 @ Shanghai, China

Asia Game Show 2010
12/24 - 12/27  

GDC 2011
2/28 - 3/4 @ San Francisco, CA

More events...
Quick Stats
97 people currently visiting GDNet.
2406 articles in the reference section.

Help us fight cancer!
Join SETI Team GDNet!
Link to us Events 4 Gamers
Intel sponsors gamedev.net search:

Contents
 Device Contexts
 Tracking
 Paint Message
 Closing Your
 Application

 Plotting Pixels
 GDI Text Functions
 Displaying Bitmaps
 One Last Thing

 Demo program
 Printable version
 Discuss this article
 in the forums



The Series
 Beginning Windows
 Programming

 Using Resources
 in Win32 Programs

 Tracking Your
 Window/Using GDI

 Introduction
 to DirectX

 Palettes and Pixels
 in DirectDraw

 Bitmapped Graphics
 in DirectDraw

 Developing the
 Game Structure

 Basic Tile Engines
 Adding Characters
 Tips and Tricks

Closing Your Application

There are three messages that seem to be pratically identical, and all deal with closing things out. They are WM_DESTROY, WM_CLOSE, and WM_QUIT. They're similar, but you need to know the difference! WM_CLOSE is sent when a window or application should be closing. When you receive a WM_CLOSE message, it's a good place to ask the user if they're sure they want to quit, if you want to do it. You know those little message boxes that are always popping up on your screen when errors or notifications occur? Well, they're easy to create. In addition to serving many functions in the final program, they're also handy for reporting debug information. The call to create your very own message box is pretty simple:

int MessageBox( HWND hWnd, // handle of owner window LPCTSTR lpText, // address of text in message box LPCTSTR lpCaption, // address of title of message box UINT uType // style of message box );

The parameters, especially the last one, require some explanation:

HWND hWnd: Sooner or later we'll get to a function that doesn't have this, I promise!

LPCTSTR lpText: This is the text that will appear in the message box. As always, you can use escape sequences like \n to format the output a little if you want.

LPCTSTR lpCaption: This is the text appearing in the message box's caption bar.

UINT uType: You can combine several different flags in order to create this parameter, which defines what kind of message box it will be. There are a lot of MB_ constants you can use, and you can combine any number of them with the | operator. Here's a list of the useful ones:

Button Definition Flags
MB_ABORTRETRYIGNORE Creates a box with "Abort," "Retry," and "Ignore" buttons.
MB_OK Creates a box with an "OK" button.
MB_OKCANCEL Creates a box with "OK" and "Cancel" buttons.
MB_RETRYCANCEL Creates a box with "Retry" and "Cancel" buttons.
MB_YESNO Creates a box with "Yes" and "No" buttons.
MB_YESNOCANCEL Creates a box with "Yes," "No," and "Cancel" buttons.
Icon Definition Flags
MB_ICONEXCLAMATION Adds an exclamation point icon to the box.
MB_ICONINFORMATION Adds an information icon to the box.
MB_ICONQUESTIION Adds a question mark icon to the box.
MB_ICONSTOP Adds a stop sign icon to the box.
Default Button Flags
MB_DEFBUTTON1 Defines the first button as the default.
MB_DEFBUTTON2 Defines the second button as the default.
MB_DEFBUTTON3 Defines the third button as the default.
MB_DEFBUTTON4 Defines the fourth button as the default.
Other Flags
MB_HELP Adds a help button to the box. A WM_HELP message is generated if the user chooses it or presses F1.
MB_RIGHT Message box text is right-justified.
MB_TOPMOST Sets the message box to always be the topmost window.

I don't know about you, but I'm starting to think that Microsoft has a programmer who does nothing but write #define statements all day! Now, the return value is 0 if the box could not be created. Otherwise, the result is one of the following:

IDABORT "Abort" button was selected.
IDCANCEL "Cancel" button was selected.
IDIGNORE "Ignore" button was selected.
IDNO "No" button was selected.
IDOK "OK" button was selected.
IDRETRY "Retry" button was selected.
IDYES "Yes" button was selected.

Those lists were so long I almost forgot what we were originally talking about. Anyway, when you receive a WM_CLOSE message, you can do two things. First, you can allow the default handler to return a value. If you do this, the application or window will close as planned. However, if you return 0, the message will have no effect. This is the basis of the following bit of code:

if (msg == WM_CLOSE) { if (MessageBox(hMainWindow, "Are you sure want to quit?", "Notice", MB_YESNO | MB_ICONEXCLAMATION) == IDNO) return(0); // otherwise, let the default handler take care of it }

Now, WM_DESTROY is a bit different. It is sent when a window is being closed. By the time you get a WM_DESTROY message, the window it applies to has already been deleted from view. If the main window closes, that does not necessarilly end the application. It will keep running, but without a window. However, when a user closes the main window, they almost always mean to close the application, so you have to post a WM_QUIT message when you receive WM_DESTROY if you want the application to end. You could use PostMessage(), but since this is a special case, there's a special function for it:

VOID PostQuitMessage(int nExitCode);

The parameter is an exit code that your application returns to Windows. Remember, WinMain() returns an int, not a void. The nExitCode parameter also becomes the wparam member of the WM_QUIT message that results. WM_QUIT represents a request to close the application, so when you get one, you should end your main loop and return wparam to Windows. Here's an example of what a simplified WinMain() function might look like with this in place:

int WinMain(HINSTANCE hinstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { // initialization stuff goes here // main loop - infinite! while (TRUE) { // check the message queue if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { if (msg.message == WM_QUIT) // exit main loop on WM_QUIT break; TranslateMessage(&msg); DispatchMessage(&msg); } // main program logic goes here } // perform any shutdown functions here - releasing objects and such return(msg.wparam); // return exit code to Windows }

Sorry about all that stuff, but it's necessary to make sure your program behaves correctly instead of causing errors for Windows -- like that ever happens! Now instead of making you any more impatient with me than you probably already are, let's look at some basic GDI graphics.




Next : Plotting Pixels