【问题标题】:Separate window message pumps and receiving WM_QUIT分离窗口消息泵和接收 WM_QUIT
【发布时间】:2018-02-02 07:22:10
【问题描述】:

我正在尝试为我的项目创建独立的窗口包装类。它大部分都在工作,但无法弄清楚如何在我的主消息泵中获取 WM_QUIT。为了学习 Windows,我不想为此使用其他库。

这是正在发生的事情的一个简单示例。

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

void TestPump()
{
    MSG msg = { 0 };

    PostQuitMessage(0);
    std::cout << "Posted WM_QUIT" << std::endl;

    while (true)
    {
        BOOL result = PeekMessage(&msg, (HWND) -1, 0, 0, PM_REMOVE);

        std::cout << "PeekMessage returned " << result << std::endl;

        if (result == 0)
            break;

        if (WM_QUIT == msg.message)
            std::cout << "got WM_QUIT" << std::endl;
    }
}

void MakeWindow()
{
    auto hwnd = CreateWindowEx(0, "Button", "dummy", 0, 0, 0, 32, 32, NULL, NULL, NULL, NULL);
    std::cout << std::endl << "Created Window" << std::endl << std::endl;
}

int main()
{
    TestPump();
    MakeWindow();
    TestPump();

    std::cin.get();

    return EXIT_SUCCESS;
}

PeekMessage 文档在这里:https://msdn.microsoft.com/en-us/library/windows/desktop/ms644943(v=vs.85).aspx

我无法找到任何使用 -1 HWND 过滤器的示例,但 MSDN 说它将接收 HWND 为 NULL 的线程消息(我已经检查过 WM_QUIT 是否如此),其中我相信 PostQuitMessage 与 WM_QUIT 有关系。

只有在创建窗口时才会出现问题。

我做错了什么,或者有更好的方法吗?

【问题讨论】:

  • 我相信您在结束语中的意思是“功能”而不是“问题”。
  • 仅供参考,我开始使用 WTL 而不是我自己的包装器,主要是因为我花在使用 Win32 玩 whackamole 的时间比实际编写应用程序的时间要多。 MFC 是一个更重量级的选择。
  • PeekMessage(&amp;msg, (HWND)-1, 0, 0, PM_REMOVE) got WM_QUIT if PostQuitMessage(0); 刚刚被调用
  • 不应该像PeekMessage(&amp;msg, NULL, 0, 0, PM_REMOVE)这样调用来获取WM_QUIT吗?
  • WM_QUIT 不是真正的消息,它是设置在PeekMessage 查找的线程上的标志。据推测,窗口过滤器会阻止它这样做。见blogs.msdn.microsoft.com/oldnewthing/20051104-33/?p=33453

标签: c++ oop winapi message-pump


【解决方案1】:

这似乎是一个有趣的案例,所以我创建了一个 mcve,尽管我很难解释这种行为:

#include <Windows.h>
#include <CommCtrl.h>

#include <iostream>
#include <cassert>

void
Create_ThreadMessagePump(void)
{
    ::MSG msg;
    ::PeekMessageW(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
    ::std::wcout << L"initialized thread message pump" << ::std::endl;
}

void
Create_Window(void)
{
    auto const hwnd{::CreateWindowExW(0, WC_STATICW, L"dummy window", 0, 0, 0, 32, 32, NULL, NULL, NULL, NULL)};
    (void) hwnd; // not used
    assert(NULL != hwnd);
    ::std::wcout << L"created window" << ::std::endl;
}

void
Test_QuitMessageExtraction(void)
{
    ::PostQuitMessage(0);
    ::std::wcout << L"posted WM_QUIT" << ::std::endl;
    for(;;)
    {   
        ::MSG msg;
        auto const result{::PeekMessageW(&msg, (HWND) -1, 0, 0, PM_REMOVE)};
        ::std::wcout << L"PeekMessageW returned " << result << ::std::endl;
        if(0 == result)
        {
            ::std::wcout << L"no more messages to peek" << ::std::endl;
            break;
        }
        if(WM_QUIT == msg.message)
        {
            ::std::wcout << L"got WM_QUIT" << ::std::endl;
        }
    }
}

int
main()
{
    //Create_ThreadMessagePump(); // does not change anything
    Test_QuitMessageExtraction();
    Create_Window();
    Test_QuitMessageExtraction();
    system("pause");
    return(0);
}

输出:

posted WM_QUIT
PeekMessageW returned 1
got WM_QUIT
PeekMessageW returned 0
no more messages to peek
created window
posted WM_QUIT
PeekMessageW returned 0
no more messages to peek

【讨论】:

  • 我正要自己做这件事,我本来应该做的。也许我需要联系陈先生。
  • @BradyH 如果 PeekMessageW 返回 0,则 msg 包含垃圾。 34359738360xCCCCCCCC 在调试模式下未初始化变量的填充值。
  • 是的,当我发布它时我意识到了这一点>.<.>
  • 如果在调用 PeekMessageW(&amp;msg, 0, 0, 0, PM_REMOVE) 中将 (HWND)-1 替换为 0,则所有操作都必须正常工作。所以问题正好在(HWND)-1
  • 如果调用PostThreadMessage(GetCurrentThreadId(), WM_QUIT, 0, 0); 而不是PostQuitMessage(0);PeekMessageW(&amp;msg, (HWND)-1, 0, 0, PM_REMOVE)一起工作
【解决方案2】:

问题似乎出在WM_QUITPostQuitMessage() 的运行方式上。你可以在这里找到信息:

Why is there a special PostQuitMessage function?.

简而言之,当队列非空时,将不会收到WM_QUIT 消息。即使您使用 -1 HWND 过滤掉其他消息,队列仍然非空,因此不会返回 WM_QUIT。创建一个窗口会导致创建多个 HWND。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-07-18
    • 1970-01-01
    • 1970-01-01
    • 2021-08-21
    • 1970-01-01
    • 2023-02-24
    • 2016-03-13
    • 1970-01-01
    相关资源
    最近更新 更多