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

Starting to make sense, Jules? Notice that the parameters to `WinProc()` are all contained within this structure, along with some others, like the time and position of the mouse when the event occurred.

So `GetMessage()` retrieves the next message from the event queue, but then what? Well, `TranslateMessage()` is called next. `TranslateMessage()` is a virtual accelerator key translator—in other words, an input cooker. Just call it and don’t worry about what it does. The final function, `DispatchMessage()`, is where all the action occurs. After the message is retrieved with `GetMessage()` and potentially processed and translated a bit with `TranslateMessage()`, the actual `WinProc()` is called by the call to `DispatchMessage()`.

`DispatchMessage()` makes the call to the WinProc, sending the appropriate parameters from the original `MSG` structure. Figure 2.9 shows the whole process in its final glory.

Figure 2.9 The mechanics of event loop message processing.

That’s it, you’re a Windows expert! If you grasp the concepts just covered and the importance of the event loop, event handler, and so on, that’s 90 percent of the battle. The rest is just details.

With that in mind, take a look at Listing 2.3. It’s a complete Windows program that creates a single window and waits for you to close it.

Listing 2.3 A Basic Windows Program

    // DEMO2_3.CPP - A complete windows program

    // INCLUDES ///////////////////////////////////////////////

    #define WIN32_LEAN_AND_MEAN  // just say no to MFC

    #include <windows.h>   // include all the windows headers

    #include <windowsx.h>  // include useful macros

    #include <stdio.h>

    #include <math.h>

    // DEFINES ////////////////////////////////////////////////

    // defines for windows

    #define WINDOW_CLASS_NAME "WINCLASS1"

    // GLOBALS ////////////////////////////////////////////////

    // FUNCTIONS //////////////////////////////////////////////

    LRESULT CALLBACK WindowProc(HWND hwnd,

                      UINT msg,

                                WPARAM wparam,

                                LPARAM lparam)

    {

    // this is the main message handler of the system

    PAINTSTRUCT    ps;    // used in WM_PAINT

    HDC        hdc;    // handle to a device context

    // what is the message

    switch(msg)

        {

        case WM_CREATE:

            {

        // do initialization stuff here

            // return success

        return(0);

        } break;

        case WM_PAINT:

        {

        // simply validate the window

        hdc = BeginPaint(hwnd,&ps);

        // you would do all your painting here

            EndPaint(hwnd,&ps);

            // return success

        return(0);

        } break;

        case WM_DESTROY:

        {

        // kill the application, this sends a WM_QUIT message

        PostQuitMessage(0);

            // return success

        return(0);

        } break;

        default:break;

        } // end switch

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

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

    } // end WinProc

    // WINMAIN ////////////////////////////////////////////////

    int WINAPI WinMain(HINSTANCE hinstance,

                HINSTANCE hprevinstance,

                LPSTR lpcmdline,

                int ncmdshow)

    {

    WNDCLASSEX winclass; // this will hold the class we create

    HWND       hwnd;      // generic window handle

    MSG       msg;          // generic message

    // first fill in the window class structure

    winclass.cbSize  = sizeof(WNDCLASSEX);

    winclass.style     = CS_DBLCLKS | CS_OWNDC |

                         CS_HREDRAW | CS_VREDRAW;

    winclass.lpfnWndProc    = WindowProc;

    winclass.cbClsExtra     = 0;

    winclass.cbWndExtra     = 0;

    winclass.hInstance      = hinstance;

    winclass.hIcon          = LoadIcon(NULL, IDI_APPLICATION);

    winclass.hCursor        = LoadCursor(NULL, IDC_ARROW);

    winclass.hbrBackground  = GetStockObject(BLACK_BRUSH);

    winclass.lpszMenuName   = NULL;

    winclass.lpszClassName  = WINDOW_CLASS_NAME;

    winclass.hIconSm        = LoadIcon(NULL, IDI_APPLICATION);

    // register the window class

    if (!RegisterClassEx(&winclass))

        return(0);

    // create the window

    if (!(hwnd = CreateWindowEx(NULL, // extended style

                     WINDOW_CLASS_NAME,   // class

                    "Your Basic Window", // title

                    WS_OVERLAPPEDWINDOW | WS_VISIBLE,

                    0,0,        // initial x,y

                    400,400,  // initial width, height

                    NULL,        // handle to parent

                    NULL,        // handle to menu

                    hinstance,// instance of this application

                    NULL)))    // extra creation parms

    return(0);

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

    // return to Windows like this

    return(msg.wParam);

    } // end WinMain

    ///////////////////////////////////////////////////////////

To compile `DEMO2_3.CPP`, simply create a Win32 `.EXE`application and add `DEMO2_3.CPP` to the project. Or if you like, you can run the precompiled program, `DEMO2_3.EXE`, off the CD-ROM. Figure 2.10 shows the program in action. It’s not much to look at, but what do you want? This is a paperback book!

Figure 2.10 `DEMO2_3.EXE` in action.

There are a couple of issues that I want to hit you with before moving on. First, if you take a close look at the event loop, it doesn’t look all that real-time. Meaning that while the program waits for a message via `GetMessage()`, the main event loop is basically blocked. This is very true; you must somehow get around this, since you need to perform your game processing continuously and handle Windows events if and when they come.

### Making a Real-Time Event Loop

This type of real-time nonwaiting event loop is easy to make. All you need is a way to test if there is a message in the message queue. If there is, you can process it; otherwise, continue processing other game logic and repeat. The function that performs this test is called `PeekMessage()`.Its prototype is almost identical to `GetMessage()`’s, as shown here:

    BOOL PeekMessage(

         LPMSG lpMsg,        // pointer to structure for message

         HWND hWnd,          // handle to window

         UINT wMsgFilterMin, // first message

         UINT wMsgFilterMax, // last message

         UINT wRemoveMsg);   // removal flags

This returns nonzero if a message is available.

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.