4

I'm working on a Windows game, and I have this:

bool game_cont;

LRESULT WINAPI WinProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch(msg)
    {
    case WM_QUIT: case WM_CLOSE: case WM_DESTROY: game_cont = false; break;
    }
    return DefWindowProc(hWnd, msg, wParam, lParam);
}

int WINAPI WinMain(/*lots of parameters*/)
{
    //tedious initialization

    //game loop
    while(game_cont)
    {
        //give message to WinProc
        if(!GameRun()) game_cont = false;
    }
    return 0;
}

and I am wondering if there is a better way to do this (ignoring timers &c. for right now) than to have game_cont be global. In short, I need to be able to exit the while in WinMain from WinProc, so that if the user presses the closes out of the game in a way other that the game's in game menu, the program wont keep running in memory. (As it did when I tested this without the game_cont.. statement in WinProc.

Oh, and on a side note, GameRun is basically a bool that returns false when the game ends, and true otherwise.

Daniel Rodriguez
  • 1,443
  • 12
  • 19

4 Answers4

11

Yes, use PeekMessage, it's the standard in game development.

This is the best approach, I believe:

int Run()
{
    MSG msg;
    while(true)
    {
        if(::PeekMessage(&msg,0,0,0 PM_REMOVE))
        {
            if(msg.message == WM_QUIT || 
                       msg.message == WM_CLOSE || 
                       msg.message == WM_DESTROY)
                break;

            ::TranslateMessage(&msg);
            ::DispatchMessage(&msg);           
        }
        else
        {
            //Run game code
                    if(!GameRun())
                         break;
        }
    }
} 

Also, look at this (specially the first answer)

Community
  • 1
  • 1
Daniel Rodriguez
  • 1,443
  • 12
  • 19
  • I would probably pass a 'game ending' value through to the GameRun code to allow it to clean up when you choose to exit the app, rather than just using 'break'. But the general structure is exactly right. – Kylotan Nov 26 '09 at 12:03
  • Thanks for the comment. Yes, I think that would be better. – Daniel Rodriguez Nov 27 '09 at 23:01
  • 2
    PeekMessage is the right approach to doing background work when no messages are present, but `WM_CLOSE` and `WM_DESTROY` should not be handled in the main message loop. Right now you're going to abort the entire program whenever any child control or invisible message helper window is destroyed! – Ben Voigt Dec 05 '13 at 20:45
1

You could use exit. Use atexit to make sure that WM_CLOSE gets to the message que when its time to exit.

I don't know what's the ultimate design here, but it's an idea.

Steinbitglis
  • 2,482
  • 2
  • 27
  • 40
0

You could make game_cont static to your main file which has WinMain/WinProc, but I don't know of a significantly better structure.

Justin Love
  • 4,397
  • 25
  • 36
0

No, don't do that.

WM_QUIT is your flag. GetMessage return value indicates when WM_QUIT is encountered.

Your main window will never receive WM_QUIT, as it isn't sent to a window. WM_CLOSE will call DestroyWindow by default, so you don't need any special handling for that. Handle WM_DESTROY by calling PostQuitMessage, which results in WM_QUIT on your thread, the special return value from GetMessage, and stops your message dispatch loop.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720