【问题标题】:Will GetMessage() return -1 in main message loop?GetMessage() 会在主消息循环中返回 -1 吗?
【发布时间】:2011-07-14 09:11:01
【问题描述】:

根据 MSDN Library 中的GetMessage API,它可能会在出现错误时返回 -1。文档提供了应该避免的常见错误的代码sn-p:

while (GetMessage( lpMsg, hWnd, 0, 0)) ...

文件说:

-1 返回值的可能性 意味着这样的代码可能会导致致命 应用程序错误。相反,使用代码 像这样:

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

我的问题是,在每个示例代码中,包括从 Visual Studio 创建的默认应用程序,来自 Microsoft,主消息循环如下所示:

while (GetMessage(&msg, NULL, 0, 0))
{
    TranslateMessage(&msg);
    DispatchMessage(&msg);
}

注意上面GetMessage的第二个参数是NULL。如果上面的代码是有效的,是不是意味着这里的GetMessage永远不会返回-1,这样就不需要处理返回值-1了?

【问题讨论】:

    标签: c++ windows winapi


    【解决方案1】:

    您应该遵循 MSDN 文档中为 GetMessage() 指定的规则。这样做很轻松,而且您的代码中也没有散布大量消息循环。

    Visual Studio 团队与 Windows 团队是分开的,他们犯的错误和其他人一样!

    我真的无法想象 GetMessage() 返回错误,但这是错误处理的本质——这并不意味着您不应该正确处理错误。

    【讨论】:

    • 我刚刚发现MSDN上有一个名为“Learn to Program for Windows in C++”的系列文章。并且BaseWindow Sample 不会在主消息循环中检查 -1 的返回值。
    【解决方案2】:

    你提到的文档说:

    如果有错误,返回值为-1。例如,如果 hWnd 是无效的窗口句柄或 lpMsg 是无效的指针,则函数将失败。

    在您的第二个示例中,这两种情况都包括在内:msg 是一个典型的堆栈分配结构,因此&msg 将始终是一个有效的指针。 NULLhwnd 参数中传递,并且是该参数的可接受值。 wMsgFilterMinwMsgFilterMax 都是零,这也是一个有效的组合。

    所以GetMessage() 在参数验证期间不会失败。文档没有明确提到它是否在其他情况下也返回 -1(例如,内存耗尽)。也就是说,我已经以与您的第二个示例相同的方式调用GetMessage() 一段时间了,但我从未见过它返回-1 并将我的消息循环变成无限循环。当然,您的里程可能会有所不同,但这样做似乎很安全。

    【讨论】:

    • 几乎所有我正在做的项目都不检查回报为-1,所以我认为我相当安全。
    【解决方案3】:

    鉴于 VS 默认为您提供错误代码,而且似乎没有人在意,这很可能不会在当前版本的 Windows 中造成问题

    GetMessage 的某些未来版本可能会返回 -1。然而,由于错误代码现在必须存在于如此多的现有应用程序中,这将破坏大量现有代码。鉴于 Microsoft 致力于向后兼容,我认为他们不太可能改变许多程序所依赖的 GetMessage 的行为。

    尽管如此,您仍应遵循文档。

    【讨论】:

    • 我从来没有因为不检查 -1 的返回而遇到麻烦,但是当我看到文档时,我很困惑。现在,我坚持文件所说的。当 GetMessage 返回 -1 时 ASSERT()。
    • VS 为默认应用程序生成的代码是正确的,因为它没有通过任何过滤器并提供有效的MSG*-argument。如果您阅读GetMessage 的文档,它会明确命名这两种错误模式。再往下看,“避免像这样的代码:” 它显示了一个带有HWND 过滤器的示例。其他错误模式也是可能的,但这些都是灾难性的,无论如何都无法合理处理。或者您将如何从损坏的消息队列中恢复?到那时,Game Over,2P UP。
    【解决方案4】:

    我的直觉(又名Raymond Chen 通灵能力)告诉我GetMessage(&msg, NULL, 0, 0) 只会在极其罕见的灾难性故障(例如消息队列损坏)的情况下返回 -1。在这种情况下,对其进行测试有点像在 C++ 程序中捕获 std::bad_alloc:当它发生时,可能为时已晚。让进程挂起(通过忽略 GetMessage() == -1)或死亡(通过不捕获 bad_alloc)是可以接受的,当然,除非所述进程正在控制核电站。

    这完全取决于你想要的正式程度。我会专门在商业应用程序中测试 -1,但不会在为个人使用而编写的小实用程序中测试。

    【讨论】:

    • 如果核电站在 Windows 上运行,我们现在都死了。
    猜你喜欢
    • 2022-01-26
    • 2018-10-14
    • 1970-01-01
    • 1970-01-01
    • 2013-11-10
    • 1970-01-01
    • 1970-01-01
    • 2019-04-12
    • 2014-08-17
    相关资源
    最近更新 更多