【问题标题】:Windows API wont quitWindows API 不会退出
【发布时间】:2013-12-15 18:22:00
【问题描述】:

由于某种原因,在我关闭此窗口后,我的程序不会退出并进入无限循环。这个问题的解决方法似乎是将GetMessage(&message,handel,0,0)改为GetMessage(&message,NULL,0,0)。但是我不明白为什么会这样。有人可以解释一下。另外我不明白为什么我调用 UpdateWindow(handel),因为没有它窗口就会显示。

#include <iostream>
#include <Windows.h>

using namespace std;

LRESULT CALLBACK EventHandler(HWND, UINT, WPARAM, LPARAM);

int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, PSTR args, int cmd)
{
    MSG message;
    HWND handel;
    WNDCLASS win_class;

    win_class.style = CS_HREDRAW | CS_VREDRAW;
    win_class.cbClsExtra = 0;
    win_class.cbWndExtra = 0;
    win_class.lpszClassName = "Window";
    win_class.hInstance = inst;
    win_class.hbrBackground = GetSysColorBrush(COLOR_3DDKSHADOW);
    win_class.lpszMenuName = NULL;
    win_class.lpfnWndProc = EventHandler;
    win_class.hCursor = LoadCursor(NULL, IDC_ARROW);
    win_class.hIcon = LoadIcon(NULL, IDI_APPLICATION);

    RegisterClass(&win_class);
    handel = CreateWindow(win_class.lpszClassName, "Window", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 350, 250, NULL, NULL, inst, NULL);
    ShowWindow(handel, cmd);
    UpdateWindow(handel);

    //Loop does not end.
    while(GetMessage(&message, handel, 0, 0))
    {
         cout << "LOOP" << endl;
         DispatchMessage(&message);
    }
    return WM_QUIT;
}

LRESULT CALLBACK EventHandler(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    static long long count = 0;
    count++;
    cout << "CALL #" << count << endl;
    if(msg == WM_DESTROY)
    {
         PostQuitMessage(0);
         return 0;
    }
    return DefWindowProc(hwnd, msg, wParam, lParam);
}

【问题讨论】:

  • 你可以通过询问你为什么曾经传递一个非NULL句柄来使这个问题更有趣。

标签: c++ windows winapi user-interface


【解决方案1】:

WM_QUIT 没有发送到任何窗口,只是放在线程的消息队列中,没有HWND,这就是它与您的过滤器不匹配的原因。

【讨论】:

  • The documentation 具有误导性。 “请注意,GetMessage 始终检索 WM_QUIT 消息,无论您为 wMsgFilterMin 和 wMsgFilterMax 指定哪些值。”正如这个问题和您的答案所示,它并不总是被检索到。但是,是否检索不依赖于 wMsgFilterMin 和 wMsgFilterMax。
  • @hvd:我将该声明解释为“wMsgFilterMin 和 wMsgFilterMax 参数不影响 WM_QUIT 处理”,但我同意它具有误导性(或充其量是模棱两可的)。
  • 虽然我很容易看出误解,但文档是正确的。如果手动将WM_QUIT 发布到特定窗口,则使用 HWND 和过滤器的代码将检索它,即使它与过滤器不匹配。
【解决方案2】:

看看MSDN中的GetMessagePostQuitMessage

如果GetMessage函数的参数hWnd为NULL,GetMessage检索属于当前线程的任何窗口的消息,以及当前线程的消息队列中hwnd值为NULL的任何消息.

PostQuitMessage 函数将 WM_QUIT 消息发布到线程的消息队列,而不是当前窗口。

【讨论】:

    【解决方案3】:

    这是锻炼“搜索 MSDN 文档”能力的好机会:

    首先,让我们查找WM_QUIT 的文档:

    表示终止应用程序的请求,并在以下情况下生成 应用程序调用 PostQuitMessage 函数。这条信息 导致 GetMessage 函数返回零。

    ...

    WM_QUIT 消息与窗口无关,因此将 永远不会通过窗口的窗口过程接收。它被检索 只能通过 GetMessagePeekMessage 函数。

    那么,我们来看看GetMessage()的文档:

    从调用线程的消息队列中检索消息。这 函数调度传入的已发送消息,直到发布的消息 可供检索。

    ...

    hWnd [in, optional] 类型:HWND

    要检索其消息的窗口句柄。窗户 必须属于当前线程。

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

    因此,您希望使用NULL 作为GetMessage() 的窗口句柄,而不是handel,因为WM_QUIT 不与任何窗口关联。

    还有来自 MSDN 的 plenty more information about how Windows programs typically handle messages


    作为旁注,窗口关闭事件的消息是WM_CLOSE,这反过来又会导致您的窗口默认被销毁。 WM_DESTROY 表示您的窗户已经在被摧毁的路上。因此,如果您想拦截关闭事件(比如要求您的用户保存任何更改),您将处理 WM_CLOSE 事件。

    此外,如GetMessage() 文档中所示,您的GetMessage() 循环实际上应该如下所示:

    BOOL bRet;
    
    while( (bRet = GetMessage( &msg, hWnd, 0, 0 )) != 0)
    { 
        if (bRet == -1)
        {
            // handle the error and possibly exit
        }
        else
        {
            TranslateMessage(&msg); 
            DispatchMessage(&msg); 
        }
    }
    

    因为GetMessage() 实际上可以返回 1、0 或 -1(尽管它返回 BOOL)。

    【讨论】:

    • 推荐阅读:When will GetMessage return -1?(所以不,循环不需要看起来像那样。)
    • @hvd:The Old New Thing 虽然是一个很棒的博客,但它并不是官方文档。另外,请注意,它永远不会仅在某些情况下返回 -1(尽管是最常见的一种,并且可能只是明智的一种)。我更喜欢编写尽可能健壮的程序,并且针对 -1 进行测试也没有什么坏处。
    • 您的回答说将其称为GetMessage(&amp;msg, NULL, 0, 0),这正是您永远不会得到-1返回值的特定情况。反正你要检查也没关系,我不会说你的循环错了,只是这里没必要。
    • @hvd:我同意你的看法。我希望看到更新的文档以反映这一点,这样我就不必在必须链接到 MSDN 时也链接到 Raymond Chen 的博客。
    猜你喜欢
    • 1970-01-01
    • 2011-12-04
    • 1970-01-01
    • 1970-01-01
    • 2017-12-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多