最近我尝试在自己的线程中放置一个窗口的消息循环,我想知道为什么它从未收到任何消息,但我已经知道Windows将消息发布到创建窗口的线程。如何在一个线程中创建一个窗口并导致另一个线程接收该窗口的消息?我已经看过PostThreadMessage函数,但我相信它还需要创建窗口的线程来监听消息,这正是我想要避免的,所以这个函数不是我需要的。
这似乎是一个常见的问题,我花了很多时间谷歌搜索答案,但我找不到答案。
答案 0 :(得分:11)
如何在一个窗口中创建一个窗口 线程并导致另一个线程 收到该窗口的消息?
简单回答......你没有。在要处理其消息的线程上创建窗口。如果这是不可能的,那么你需要重新思考你的方法。
答案 1 :(得分:7)
Windows消息泵实际上只是一个while
循环,它使用PeekMessage()
从队列中选择消息并调用您的Windows WndProc函数。还有一点比这更多,但那是基本的操作。
因此,while
循环运行的任何线程都是您的窗口可以“运行”的唯一线程。这就是我见过的每个Windows应用程序的构建方式。
但是我曾经想过,经过多付努力,应该可以在多个线程中构建一个带有Windows的Windows应用程序。我没有任何代码可以告诉你,因为我考虑过这个问题已经很久了,但我考虑了两种方法:
在主线程中保留一个消息泵。但是修改消息泵代码,以便在while
中根据特定QueueUserAPC
运行的线程使用HWND
将消息分派给工作线程。此时需要查找映射,这可能是计算上昂贵的。
在工作线程中创建一个全新的消息泵。您必须编写所有while
代码,但这很简单,Petzold's classic book将为您提供执行此操作所需的所有工具。
请注意,对于我能想到的任何应用程序,从架构的角度来看,这种方法是没有意义的。如果您合理地构建应用程序,则根本不需要Windows在多个线程中运行。窗口处理发生在一个线程中,操作发生在另一个(或许多)中。然而,我有一个有趣的研究领域,这就是我走这条道路的原因。长话短说,我几乎可以肯定你不需要这样做而且不应该这样做 - 但这可能就是你应该这样做的。
答案 2 :(得分:5)
这是不可能的。每个窗口都属于创建它的线程,并且无法传输所有权。
这不是将您的消息泵放在另一个线程中的问题。每个线程都有自己的消息队列。当您向窗口发送或发送消息时,操作系统会检查哪个线程拥有该窗口并将消息定向到该线程的消息队列。线程无法读取任何消息队列但是它们自己的消息队列,所以你不能让一个线程处理另一个线程的窗口的消息。
您可以将消息重新发送到另一个线程,如the first idea in John's answer,但作为通用消息处理程序,将变得比它的价值更复杂。许多消息用于修改窗口的状态,但除了窗口自己的线程外,您无法修改状态。发送一些消息的目的是获得有意义的返回值,但是在处理消息之前你不知道要返回什么,所以你必须阻塞,等待工作线程处理消息。
你最好找出一小组真正可以卸载到工作线程并专门处理它们的消息。一旦你这样做,你就不会有一个窗口,其消息在不同的线程中处理;你只需要一个普通的工作线程,理由就不那么容易了。
如果发送发送到您的窗口的消息需要大量时间来处理,但发送者要么不需要知道结果,要么在完成处理之前知道结果,然后你可以通过调用ReplyMessage
来提供早期响应。这使得发送线程继续运行,而窗口的线程可以执行额外的工作。
答案 3 :(得分:2)
您可以看到AttachThreadInput是否适合您 - 它可以让您处理来自其他线程的消息。
这实际上不是一个常见的问题,因为你几乎总是在创建它的线程中处理一个窗口的消息。见Goz的回答;我同意。
请注意,将消息处理放入另一个线程中您将无法获得任何好处。不要将GUI任务分解为多个线程,将处理/后台任务分解为线程。
答案 4 :(得分:-1)
看到这个:
MSDN:http://msdn.microsoft.com/en-us/library/ms644946(v=vs.85).aspx
发布消息的线程必须已创建消息队列,否则 调用PostThreadMessage失败。使用以下方法来处理这种情况。
1.创建一个事件对象,然后创建该线程。
2.在调用PostThreadMessage之前,使用WaitForSingleObject函数等待事件设置为信号状态。
3.在将要发布消息的线程中,如此处所示调用PeekMessage以强制系统创建消息队列。
PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE)
4.设置事件,以指示线程已准备好接收发布的消息。