如何处理来自单独线程的窗口消息?

时间:2009-12-26 19:05:48

标签: windows multithreading winapi

我希望启动一个单独的线程来处理窗口消息(通过阻塞GetMessage循环),但之后仍然在初始线程中创建窗口。

在单独的线程中,一旦启动,我用PM_NOREMOVE调用PeekMessage以确保存在消息队列(这是必要的吗?),然后是..

AttachThreadInput(initial thread id,GetCurrentThreadId(),true)

..在最终进入消息循环之前

我还没有使用互斥锁或cs来确保及时发生这种情况,但为了简单起见,我只是在我的初始线程中使用Sleep语句。

无论如何,窗口消息似乎不会被单独的线程截获。

我不确定我是否正确地这样做,并希望得到任何可能的指导。两个线程都在同一个进程中

谢谢大家

2 个答案:

答案 0 :(得分:7)

这不是AttachThreadInput所做的。即使将输入队列附加到另一个线程,Windows仍然具有线程关联。只有该窗口的线程才能从队列中删除给定窗口的队列中的消息。

AttachTheadInput做的是让两个线程共享一个输入队列。这允许他们查询有关输入状态的信息,并知道另一个线程将为同一查询获得相同的答案。例如,一个线程可以调用GetAsyncKeyState并知道答案反映了另一个线程的键状态。

它允许两个或多个线程与输入队列具有相同的关系,并且与Windows 3x中的进程具有相同的关系。这就是这个API存在的原因;这样复杂的多进程应用程序就可以从Win 3x移植到Win95 / WinNT。

答案 1 :(得分:2)

这似乎是从主线程启动窗口创建的最佳方式,而在单独的循环线程中处理它们的消息是使用自定义消息,可以将其发送到单独的线程 - 从而允许它创建窗口,但仍然允许从初始线程调用该操作:

1)分配自定义消息,并创建一个结构来保存窗口初始化参数:

message_create_window = WM_USER + 0;
class Message_create_window{
    Message_create_window(...);
};

2)不要调用CreateWindow(Ex),而是使用类似下面的内容,传递相关窗口创建参数:

PostThreadMessage(
    thread.id,
    message_create_window,
    new Message_create_window(...),
    0
);

3)在你的ui处理线程的消息泵中处理自定义消息,提取创建参数,&之后免费:

MSG msg;
GetMessage(&msg,0,0,0);
...
switch(msg->message){
    ...
    case message_create_window:{
        Message_create_window *data=msg->wParam;
        CreateWindowEx(data->...);
        delete data;
    }break;
    ...

然而,这确实有以下副作用:

  • 窗口将异步创建。如果需要初始线程阻塞直到创建窗口(或者实际上,窗口的存在可以被断言),那么必须使用线程同步工具(例如事件)
  • 在与窗口交互时应该小心(毕竟它是一个多线程应用程序)

如果这个答案中有任何重大漏洞,或者这似乎是一种可怕的方法,请纠正我。 (这仍然是我的问题,而且我正在努力找到实现这一目标的最佳方法)