【问题标题】:Window in Win32 application won't close normallyWin32 应用程序中的窗口无法正常关闭
【发布时间】:2015-09-27 01:21:58
【问题描述】:

原来的问题:

尽管我的窗口过程函数能够检测到WM_CLOSE 消息并调用PostQuitMessage 并让Windows 继续使用DefWindowProc 处理窗口消息,但我有一个窗口在创建后无法立即关闭。

但是,通过拖动标题栏移动窗口后,似乎可以正常关闭了。

我的窗口过程函数的代码如下:

LRESULT CALLBACK OnEvent(HWND handle, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
        case WM_QUIT:
        {
            printf("WM_QUIT\n");
            break;
        }
        case WM_CLOSE:
        {
            printf("WM_CLOSE\n");
            PostQuitMessage(0);
            return 0;
        }
    }
    return DefWindowProc(handle, message, wParam, lParam);
}

那么除了将WM_MOVE消息发送到我的窗口或在WM_CLOSE case块中使用exit(0)之外,如何确保我的窗口在创建后可以立即关闭?

新问题:

在将NULL 传递给GetMessageWhWnd 参数后,窗口现在可以正常关闭,从而回答了我之前的问题。

那么,为什么GetMessageW函数之前没有使用提供的唯一窗口句柄检索WM_QUIT消息,而不是使用NULL作为hWnd参数?

【问题讨论】:

  • 未测试,调用PostQuitMessage(0);而不是调用DefWindowProc获取消息WM_QUIT可能不好。
  • 它可能对你有用。 msdn.microsoft.com/en-us/library/windows/desktop/… 并且,在printf("WM_QUIT\n"); 之后,没有break;。好吗?
  • WM_QUIT 永远不会进入您的 WndProc,除非出现严重错误。
  • @gyu-don DestroyWindow 在我的主函数中的“GetMessage 循环”之后已经被调用。

标签: c winapi


【解决方案1】:

正确编写的消息循环永远不会将WM_QUIT 消息发送到窗口过程,它只会在GetMessage() 在收到WM_QUIT 消息时返回0 时打破循环:

GetMessage function

如果函数检索到 WM_QUIT 以外的消息,则返回值非零。

如果函数检索到 WM_QUIT 消息,则返回值为零。

如果有错误,返回值为-1。例如,如果 hWnd 是无效的窗口句柄或 lpMsg 是无效的指针,则函数将失败。要获取扩展的错误信息,请调用 GetLastError。

响应WM_CLOSE,你应该直接调用DestroyWindow()而不是PostQuitMessage()DefWindowProc(WM_CLOSE)的默认行为是为你调用DestroyWindow())。你需要一个WM_DESTROY 处理程序,然后应该调用PostQuitMessage()

LRESULT CALLBACK OnEvent(HWND handle, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
        case WM_CLOSE:
        {
            printf("WM_CLOSE\n");
            DestroyWindow(handle);
            return 0;
        }

        case WM_DESTROY:
        {
            printf("WM_DESTROY\n");
            PostQuitMessage(0);
            return 0;
        }
    }
    return DefWindowProc(handle, message, wParam, lParam);
}

这在 MSDN 上有记录:

Closing the Window

这是该页面的流程图:

关于GetMessage() 的问题,如果你仔细阅读GetMessage()PostQuitMessage() 的文档,你会发现PostQuitMessage() 发布的WM_QUIT 消息不是一个窗口 em> 消息。将非 NULL HWND 传递给 GetMessage() 只会从 PostMessage()SendMessage() 检索用于特定 HWND 1 的消息。 GetMessage() 将忽略不属于该HWND 的任何消息,其中包括来自PostThreadMessage()PostQuitMessage()线程 消息。将 NULL HWND 传递给 GetMessage() 允许它返回任何待处理的消息,包括 WM_QUIT

1 这样做很危险,顺便说一句:The dangers of filtering window messages

【讨论】:

  • 好吧,虽然我现在明白我的错误,但那很尴尬。
【解决方案2】:

当我在循环中调用 GetMessage() 时,我遇到了这个确切的问题,主窗口的句柄作为第二个参数:

GetMessage(&msg, hMainWindow, 0, 0)

而不是NULL来指定我要为整个线程/应用程序实例处理消息:

GetMessage(&msg, NULL, 0, 0)

WM_CLOSE 消息会导致 WM_QUIT 消息,但是当 GetMessage() 只查找特定窗口的消息时,它会忽略这些消息。来自documentation

如果 hWnd 为 NULL,GetMessage 检索属于当前线程的任何窗口的消息,以及当前线程的消息队列中 hwnd 值为 NULL 的任何消息(参见 MSG 结构)。因此,如果 hWnd 为 NULL,窗口消息和线程消息都会被处理。

究竟是什么导致窗口移动以使随后的关闭尝试成功,但我仍然无法理解。

【讨论】:

    【解决方案3】:

    我发现的另一个问题是,当您设置窗口类 (WNDCLASSEX) 窗口过程 (lpfnWndProc) 时,我已将其设置为默认窗口过程并且没有使用自定义构建的窗口过程。所以当你关闭它时,什么都不会发生。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-04-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-01-25
      相关资源
      最近更新 更多