【问题标题】:How to handle messages from multiple windows如何处理来自多个窗口的消息
【发布时间】:2019-04-26 09:39:02
【问题描述】:

所以我有多个窗口正在运行,我想为所有窗口处理消息,这样它们就不会挂起。到目前为止,我已经尝试了多种方法:

1) 把它变成一个线程(有点愚蠢,但我试过了):

auto ProcessThread(
    std::vector<HWND> Windows
) -> void
{
    for (;;)
    {
        MSG Msg1 = decltype(Msg1){0x00};
        MSG Msg2 = decltype(Msg2){0x00};

        GetMessageW(&Msg1, Windows.at(0), 0, 0);
        GetMessageW(&Msg2, Windows.at(1), 0, 0);

        TranslateMessage(&Msg1);
        TranslateMessage(&Msg2);

        DispatchMessageW(&Msg1);
        DispatchMessageW(&Msg2);
    }

    return;
}

...

    std::vector<HWND> Windows = { lpScreen.m_WindowHandle, lpPopup.m_WindowHandle };
    HANDLE hThread = CreateThread(nullptr, 0, reinterpret_cast<LPTHREAD_START_ROUTINE>(ProcessThread),
        &Windows, 0, nullptr);

    while (WAIT_TIMEOUT == WaitForSingleObject(hThread, 1000)) {}

    CloseHandle(hThread);

2) 只是填充第二个消息循环

    MSG Msg1 = decltype(Msg1){0x00};
    MSG Msg2 = decltype(Msg2){0x00};

    while (GetMessageW(&Msg1, Hwnd1, 0, 0) && GetMessageW(&Msg2, Hwnd2, 0, 0))
    {
        TranslateMessage(&Msg1);
        TranslateMessage(&Msg2);

        DispatchMessageW(&Msg1);
        DispatchMessageW(&Msg2);
    }

3) 第二个的其他变体


到目前为止,所有这些都使我的窗口无法移动,并给了我加载光标。

有什么想法吗?

【问题讨论】:

  • 考虑到GetMessage blocks 第二种选择有点缺陷。
  • 要接收所有窗口的消息,只需不要过滤。要了解该代码损坏的原因,请参阅The dangers of filtering window messages
  • 我不明白 "it" 是什么或 "防止被卡住" 应该是什么意思。您当然希望您的消息循环为所有窗口以及线程消息调度 all 消息(WM_QUIT 是后者的一个突出示例)。如果您需要GetMessage 的非阻塞版本,请使用PeekMessage,如果您需要等待其他可等待对象,请使用MsgWaitForMultipleObjects
  • 在所有初学者教程中发现的标准、简单的消息循环服务于多个窗口。如果您需要帮助解决代码中的问题,您必须首先明确该问题是什么。由于我们其他人很乐意管理具有多个窗口的应用程序,显然您正在做一些不同的事情。但是什么?
  • 您睡眠不足的事实与我们无关,实际上使您的问题黯然失色。我们不是来为那些为什么不管理他们的时间和截止日期的人提供一对一的个人支持。如果您找不到时间睡觉(或者确实无法学习 Win32 GUI 编程的基础知识),那是您的问题,而不是我们的问题。这是一个提供对其他访问者有用的问题的网站。再次阅读您发布的内容,并问问自己是否认为它符合该描述。其他对您有用的资源:@​​987654324@ 和 tour

标签: c++ winapi


【解决方案1】:

你的代码有几个问题:

  1. ProcessThread() 被声明为 CreateThread() 完全错误,编译器通常会为此尖叫,但是您使用错误的类型转换来使编译器安静,而不是修复错误。因此,ProcessThread() 将无法在运行时正确接收vectorProcessThread() 需要看起来更像这样:

    DWORD WINAPI ProcessThread(LPVOID lpParam)
    {
        std::vector<HWND> *Windows = static_cast<std::vector<HWND>*>(lpParam);
        ...
        return 0;
    }
    
    ...
    
    HANDLE hThread = CreateThread(..., &ProcessThread, &Windows, ...);
    
  2. 你的线程的消息循环都是错误的。每次循环迭代调用GetMessage() ONCE,并且根本不指定任何过滤HWND(请参阅The dangers of filtering window messages)。它将从消息队列中提取下一条可用消息,然后您可以将其传递给 DispatchMessage() 以将消息发送到相应的 WndProc 以进行进一步处理。

    DWORD WINAPI ProcessThread(LPVOID lpParam)
    {
        std::vector<HWND> *Windows = static_cast<std::vector<HWND>*>(lpParam);
        MSG Msg;
    
        while (GetMessageW(&Msg, 0, 0, 0) > 0)
        {
            TranslateMessage(&Msg);
            DispatchMessageW(&Msg);
        }
    
        return 0;
    }
    
  3. 您正在创建一个工作线程,只是为了等待它终止,而无需并行执行任何其他操作。这使得工作线程完全没用。你需要摆脱那个线程,特别是考虑到......

  4. ...您正在一个单独的线程中运行消息循环,而不是创建窗口的线程。你根本不能这样做!一个窗口具有线程亲和性(Get|Peek)Message() 只接收与调用线程关联的窗口的消息,因此只有创建窗口的线程才能接收该窗口的消息。

你在考虑你的代码设计。您可以将其大大简化为:

std::vector<HWND> Windows = { lpScreen.m_WindowHandle, lpPopup.m_WindowHandle };
MSG Msg;

while (GetMessageW(&Msg, 0, 0, 0) > 0)
{
    TranslateMessage(&Msg);
    DispatchMessageW(&Msg);
}

如果lpScreen.m_WindowHandlelpPopup.m_WindowHandle 是调用线程中唯一可用的窗口,那么您甚至根本不需要vector

但是,如果您对仅处理特定窗口的消息感兴趣,这确实会出现问题。上面的代码将接收调用线程中所有窗口的消息。如果这不是您想要的,那么您可以(但不应该!)过滤vector 中的特定窗口,例如:

std::vector<HWND> Windows = { lpScreen.m_WindowHandle, lpPopup.m_WindowHandle };
MSG Msg;

for(auto h : Windows)
{
    while (PeekMessageW(&Msg, h, 0, 0, PM_REMOVE))
    {
        TranslateMessage(&Msg);
        DispatchMessageW(&Msg);
    }
}

但如果你不小心,这可能会导致其他窗口的消息不足。

否则,您只需要使用单独的线程来创建和处理您感兴趣的窗口。

【讨论】:

    猜你喜欢
    • 2011-10-24
    • 2010-11-24
    • 2022-01-21
    • 2017-05-29
    • 1970-01-01
    • 1970-01-01
    • 2014-11-27
    • 1970-01-01
    • 2010-11-10
    相关资源
    最近更新 更多