views:

231

answers:

2

I'm programming a little game, and I set the lpfnWndProc to DefWindowProc and after that, I made a loop in that way:

    MSG lastMessage;
 while (true)
 {
  if (PeekMessage(
   &lastMessage, 
   this->getWindow(), 
   0, 0, 
   PM_REMOVE))
  {
   TranslateMessage(&lastMessage);
   DispatchMessage(&lastMessage);
  }
 }

So how do I handle the Close Window event in that case?

+2  A: 

First of all, this is not how you write a message loop: it will take 100% CPU while waiting for messages, and won't remove messages for other windows from the queue. It will also never terminate. See here for an example of a message loop.

About closing windows: DefWindowProc will handle WM_CLOSE automatically and destroy your window. If you want your application to terminate when the window is closed, you need to handle WM_DESTROY and call PostQuitMessage(0) from it. This means you will need your own window procedure instead of DefWindowProc.

interjay
I know it'll take 100% CPU, I'm going to use the DirectX Device->Present function to sleep.I know I can write my own function instead of DefWindowProc,but I'm using classes and I want to handle the message fromin the class, I can't use callbacks to do so because callbacksmsut be in global scope or static scope.Is there a way to prevent DefWindowProc to handle WM_CLOSE?
Tamir
I suppose you can avoid calling DispatchMessage when the message is `WM_CLOSE` if you really don't want a window proc.
interjay
You do need to process all messages for all windows. If you dont remove them from the queue who will? they'll just build up and eventually exhust your message queue.
Chris Becke
A: 
  1. If you want WindowProc to be handled by a class, you do something like

    class CWindow 
    {
      static LRESULT WindowProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
      { 
        CWindow* self;
        if(uMsg == WM_CREATE)
        {
          self = (CWindow*)((LPCREATESTRUCT)lParam)->lplpCreateParams;
        }
        else
          self = GetWindowLong(hwnd,GWL_USERDATA);
        if(self){
          switch(uMsg){
          case WM_CREATE:
            return self->OnCreate(hwnd,(LPCREATESTRUCT)lParam);
          case WM_CLOSE:
            self->OnClose();
            return 0;
          // etc.
          }
        }
        return DefWindowProc(hwnd,uMsg,wParam,lParam);
      }
      int OnCreate(HWND hwnd,LPCREATESTRUCT lpcs)
      {
        m_hwnd = hwnd;
        SetWindowLong(m_hwnd,GWL_USERDATA,this);
        return 0;
      }
    }
    

Making sure of course to pass 'this' as the last parameter to CreateWindow(Ex).

Next, In your message loop, you MUST check for WM_QUIT messages and use that as a cue to exit the loop. Also, NEVER do a filter on hwnd as that will prevent your application loop from dispatching messages for other windows on your thread. And many windows libraries create message windows on threads to facilitate inter process (and thread) comms. If you dont process all windows messages then (a) your game will eventually run out of memory, and (b) the entire system may start to act funny as your application will make IPC messages deadlock, or time out.

Also, WM_CLOSE is (usually) sent via SendMessage, not PostMessage. Sent messages are delivered straight to the window proc and can't be filtered in the app loop.

Chris Becke