Tricks of the Windows Game Programming Gurus:The Windows Programming Model

All ITKnowledge Source Code Search Tips Advanced Search |

| Tricks of the Windows Game Programming Gurus by Andre LaMothe Sams, Macmillan Computer Publishing ISBN: 0672313618 Pub Date: 09/27/99

Search this book:

Previous | Table of Contents | Next

To accomplish this feat, you must validate the client rectangle of the window. There are a number of ways to do this, but the simplest is to put a call to `BeginPaint()`—`EndPaint()`. This calling pair validates the window and fills the background with the background brush previously stored in the Windows class variable `hbrBackground`. Once again, here’s the code for the validation:

          // begin painting

       hdc = BeginPaint(hwnd,&ps);

       // you would do all your painting here

           EndPaint(hwnd,&ps);

There are a couple of things going on here that I want to address. First, notice that the first parameter to each call is the window handle `hwnd`. This is necessary because the `BeginPaint()`—`EndPaint()` functions can potentially paint in any window of your application, so the window handle indicates which one you’re interested in messing with. The second parameter is the address of a `PAINTSTRUCT` structure that contains the rectangle that you must redraw. Here’s what a `PAINTSTRUCT` looks like:

    typedef struct tagPAINTSTRUCT

            {

            HDC  hdc;

            BOOL fErase;

            RECT rcPaint;

            BOOL fRestore;

            BOOL fIncUpdate;

            BYTE rgbReserved[32];

            } PAINTSTRUCT;

You don’t really need to worry about this until later, when we talk about the Graphics Device Interface or GDI. But the most important field is `rcPaint`, which is a `RECT` structure that contains the minimum rectangle that needs to be repainted. Take a look at Figure 2.8 to see this. Notice that Windows tries to do the least amount of work possible, so when the contents of a window are mangled, Windows at least tries to tell you the smallest rectangle that you can repaint to restore the contents. And if you’re interested in the `RECT` structure, it’s nothing more than the four corners of a rectangle, as shown here:

    typedef struct tagRECT

            {

            LONG left;   // left x-edge of rect

            LONG top;    // top y-edge of rect

            LONG right;  // right x-edge of rect

            LONG bottom; // bottom y-edge of rect

            } RECT;

And the last thing that you’ll notice about the call to `BeginPaint()` is that it returns a handle to a graphics context or `hdc`:

    HDC hdc; // handle to graphics context

    hdc = BeginPaint(hwnd,&ps);

Figure 2.8 Repainting the invalid region only.

A graphics context is a data structure that describes the video system and drawing surface. It’s magic, as far as we are concerned; you just have to retrieve one if you want to do any graphics. That’s about it for the `WM_PAINT` message—for now.

The `WM_DESTROY` message is actually quite interesting. `WM_DESTROY` is sent when the user closes the window. However, this only closes the window, not the application. The application will continue to run, but without a window. You need to do something about this. In most cases, when the user kills the main window, he intends for the application to terminate. Thus, you must facilitate this by sending a message yourself! The message is called `WM_QUIT`. And since this message is so common, there’s a function to send it for you, called `PostQuitMessage()`.

All you need to do in the `WM_DESTROY` handler is clean up everything and then tell Windows to terminate your application with a call to `PostQuitMessage(0)`. This, in turn, puts a `WM_QUIT` into the message queue, which at some point causes the main event loop to bail.

There are a couple of details you should know about in the WinProc handler we have been analyzing. First, I’m sure you have noticed the `return(0)` after each handler body. This serves two purposes: to exit the WinProc and to tell Windows that you handled the message. The second important detail is the default message handler, `DefaultWindowProc()`. This function is a passthrough that passes messages that you don’t process onto Windows for default processing. Therefore, if you don’t handle the message, make sure to always end all your event handler functions with a call like this:

    // process any messages that we didn't take care of

    return (DefWindowProc(hwnd, msg, wparam, lparam));

I know this may all seem like overkill and more trouble than it’s worth. Nevertheless, once you have a basic Windows application skeleton, you just copy it and add your own code. My main goal, as I said, is to help you create a DOS32-looking game console that you can use and almost forget that any Windows stuff is going on. Anyway, let’s move on to the last part—the main event loop.

### The Main Event Loop

The hard part is over! The main event loop is so simple, I’m just going to blurt it out and then talk about it:

    // enter main event loop

    while(GetMessage(&msg,NULL,0,0))

         {

         // translate any accelerator keys

         TranslateMessage(&msg);

         // send the message to the window proc

         DispatchMessage(&msg);

         } // end while

That’s it? Yup! Let’s see what’s going on here, shall we? The main `while()` is executed as long as `GetMessage()` returns a nonzero value. `GetMessage()` is the workhorse of the main event loop, and its sole purpose is to get the next message from the event queue and process it. You’ll notice that there are four parameters to `GetMessage()`. The first one is important to us; however, the remaining parameters are set to `NULL` and 0. Here’s the prototype, for reference:

    BOOL GetMessage(

         LPMSG lpMsg,         // address of structure with message

         HWND hWnd,           // handle of window

         UINT wMsgFilterMin,  // first message

         UINT wMsgFilterMax); // last message

The `msg` parameter is (yes, you guessed it) the storage for Windows to place the next message in. However, unlike the `msg` parameter for `WinProc()`, this `msg` is a complex data structure rather than just an integer. Remember, by the time a message gets to the WinProc, it has been “cooked” and split apart into its constituent parts. Anyway, here is the `MSG` structure:

    typedef struct tagMSG

            {

            HWND hwnd;     // window where message occurred

            UINT message;  // message id itself

            WPARAM wParam; // sub qualifies message

            LPARAM lParam; // sub qualifies message

            DWORD  time;   // time of message event

            POINT  pt;     // position of mouse

            } MSG;

Previous | Table of Contents | Next

Copyright © Macmillan Computer Publishing, Inc.

Products | Contact Us | About Us | Privacy | Ad Info | Home
Use of this site is subject to certain Terms & Conditions, Copyright © 1996-2000 EarthWeb Inc. All rights reserved. Reproduction in whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Read EarthWeb's privacy statement.