【问题标题】:How do I destroy a Window correctly?如何正确销毁 Window?
【发布时间】:2009-11-01 10:07:51
【问题描述】:

我正在编写一个小游戏,我将 lpfnWndProc 设置为 DefWindowProc 之后,我以这种方式制作了一个循环:

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

那么在这种情况下我该如何处理关闭窗口事件呢?

【问题讨论】:

    标签: c++ winapi window message terminate


    【解决方案1】:

    首先,这不是您编写消息循环的方式:它在等待消息时会占用 100% 的 CPU,并且不会从队列中删除其他窗口的消息。它也永远不会终止。有关消息循环的示例,请参阅 here

    关于关闭窗口:DefWindowProc 将自动处理 WM_CLOSE 并销毁您的窗口。如果您希望您的应用程序在窗口关闭时终止,您需要处理WM_DESTROY 并从中调用PostQuitMessage(0)。这意味着您将需要自己的 window procedure 而不是 DefWindowProc

    【讨论】:

    • 我知道它会占用 100% CPU,我将使用 DirectX Device->Present 函数来休眠。我知道我可以编写自己的函数而不是 DefWindowProc,但是我正在使用类并且我想处理来自类中的消息,我不能使用回调来这样做,因为回调必须在全局范围或静态范围内。有没有办法阻止 DefWindowProc 处理 WM_CLOSE?
    • 如果你真的不想要一个window proc,我想你可以避免在消息为WM_CLOSE时调用DispatchMessage。
    • 您确实需要处理所有窗口的所有消息。如果您不将它们从队列中删除,谁会?它们只会建立并最终耗尽您的消息队列。
    【解决方案2】:
    1. 如果你想让 WindowProc 由一个类来处理,你可以这样做

      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;
        }
      }
      

    当然要确保将“this”作为最后一个参数传递给 CreateWindow(Ex)。

    接下来,在您的消息循环中,您必须检查 WM_QUIT 消息并将其用作退出循环的提示。此外,永远不要对 hwnd 进行过滤,因为这会阻止您的应用程序循环为线程上的其他窗口分派消息。许多 Windows 库在线程上创建消息窗口以促进进程间(和线程)通信。如果您不处理所有 Windows 消息,那么 (a) 您的游戏最终会耗尽内存,并且 (b) 整个系统可能会开始变得有趣,因为您的应用程序会使 IPC 消息死锁或超时。

    此外,WM_CLOSE(通常)是通过 SendMessage 发送的,而不是 PostMessage。发送的消息直接传递到窗口 proc,不能在应用循环中过滤。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-30
      • 2011-04-06
      • 2017-01-20
      • 1970-01-01
      • 1970-01-01
      • 2013-06-14
      • 2011-01-15
      • 1970-01-01
      相关资源
      最近更新 更多