【问题标题】:Does PostQuitMessage() goes into WM_DESTROY or WM_CLOSE?PostQuitMessage() 是否进入 WM_DESTROY 或 WM_CLOSE?
【发布时间】:2013-01-26 14:43:03
【问题描述】:

我正在尝试使用 Win32 API 创建一个非常基本的窗口,但我已经很久没有这样做了。

我认为我的消息循环没问题,但是当我关闭打开的窗口时,应用程序仍在运行。看起来消息循环永远不会收到WM_QUIT 消息。但是,我打电话给PostQuitMessage,一个消息框确认我打电话给它。

这个极简代码有什么问题?

#include <Windows.h>

LRESULT CALLBACK window_proc(HWND hwnd, UINT msg,
        WPARAM w_param, LPARAM l_param) {
    switch (msg) {
    case WM_DESTROY:
        MessageBox(NULL, L"destroy", L"info", MB_OK);
        PostQuitMessage(0);
        break;

    default:
        return DefWindowProc(hwnd, msg, w_param, l_param);
    }

    return 0;
}

int CALLBACK WinMain(HINSTANCE h_instance, HINSTANCE h_prev_instance,
        LPSTR cmd_line, int n_cmd_show) {
    WNDCLASS wnd_class;
    HWND hwnd;
    MSG msg;
    BOOL ret;

    wnd_class.cbClsExtra = 0;
    wnd_class.cbWndExtra = 0;
    wnd_class.hbrBackground = (HBRUSH) GetStockObject(BLACK_BRUSH);
    wnd_class.hCursor = LoadCursor(NULL, IDC_ARROW);
    wnd_class.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wnd_class.hInstance = h_instance;
    wnd_class.lpfnWndProc = window_proc;
    wnd_class.lpszClassName = L"MyWindowClass";
    wnd_class.lpszMenuName = NULL;
    wnd_class.style = 0;
    if (!RegisterClass(&wnd_class)) {
        MessageBox(NULL, L"cannot register window class",
            L"error", MB_OK | MB_ICONERROR);
    }

    hwnd = CreateWindow(
        L"MyWindowClass",
        L"",
        WS_OVERLAPPEDWINDOW | WS_VISIBLE,
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        NULL,
        NULL,
        h_instance,
        NULL
    );

    while ((ret = GetMessage(&msg, hwnd, 0, 0)) != 0) {
        if (ret == -1) {
            MessageBox(NULL, L"error", L"", MB_OK);
        } else {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

    MessageBox(NULL, L"quitting now", L"info", MB_OK);

    return msg.wParam;
}

GetMessage 文档说函数在读取WM_QUIT 消息时返回 0。怎么会调用PostQuitMessage 而GetMessage 永远不会返回0?

谢谢你,Win32 大师。

【问题讨论】:

  • @KenWhite 传统上,WM_CLOSE 调用DestroyWindow(),它发送WM_DESTROY,您的处理程序调用PostQuiteMessage(),它将WM_QUIT 发布到线程消息队列,导致GetMessage() 返回0。这就是他首先来到这里的原因。我唯一觉得奇怪的是WM_DESTROY 处理程序中的消息框。如果我面前有一个 windows 盒子,我会试试这个,因为它一定是一个太简单的问题。
  • @KenWhite,根据Microsoft documentation“它通常用于响应 WM_DESTROY 消息。”
  • @MarkRansom 我同意(希望在之前的评论中很明显)。
  • @WhozCraig 和@MarkRansom:知道了。我读的是remarks,而不是主题。删除我的 cmets。感谢您的更正 - 我不得不做这些事情已经太久了。 :-)
  • @eepp 想我明白了。发布传入(没有双关语)。

标签: c windows winapi


【解决方案1】:

这是您的 GetMessage() 循环。

您将窗口句柄传递给该循环,从而过滤掉所有应用程序线程消息,并且只接收到那个窗口的消息。 .

改变这个:

while ((ret = GetMessage(&msg, hwnd, 0, 0)) != 0) 
//  Note window handle =========^

到这里:

while ((ret = GetMessage(&msg, NULL, 0, 0)) != 0) 
//  Note no handle =============^

您的应用程序线程队列现在应该由您的GetMessage() 循环监控。

原因: GetMessage() 调用可以定制为监视特定窗口句柄的消息队列。应用程序 WM_QUIT 未发布到窗口句柄队列;它被发布到线程消息队列,它只能通过使用GetMessage()(也可能是PeekMessage(),但它太长我记不住了)从队列中拉出消息no要专门监视的目标窗口句柄。

【讨论】:

  • 我刚刚发现(通过查看在线演示),回到这里回答并找到了您的答案。这是正确的!谢谢你。但是,ret 变量有什么问题?
  • @eepp @​​987654330@ 的返回类型是BOOL。我知道,它定义为int,但从技术上讲,微软希望所有BOOL API 只检查零(FALSE)或非零值。不应依赖除零以外的任何特定值。如果需要的不仅仅是零和非零返回值,API 将返回 int 或类似的,而不是带有关于可能返回值的特定文档。我希望这是有道理的。
  • 很高兴知道,但看看他们的例子right here。我只是不知道他们为什么让这个函数返回BOOL,如果他们想让我们检查 -1、0 和任何积极的东西......
  • @eepp 你对不一致是绝对正确的。它可能是一条很长的遗产线,可以追溯到二十多年前。如果GetMessage() 可以返回除特定零或非特定非零之外的任何特定应可测试的东西,则不应将其声明为 BOOL。我觉得讽刺的是“'TRUE'的不同版本”。但你是对的,他们记录了这一点,所以我会带着它跑(全程捂着鼻子)。由于他们确实记录了这个案例,我将从发布的答案中提取评论。
  • 为了增加欢乐,从 wndproc 返回的新定义是 INT_PTR。 (DialogProcs 是那些 BOOL ......不幸的是他们仍然是)。如前所述,这些东西来自 16 位实模式时代。
猜你喜欢
  • 2010-10-15
  • 2011-03-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多