Changing a Window's message loop thread
Recently I tried putting a window's message loop in its own thread, and I wondered why it never received any messages, but I have learned that Windows posts messages to the thread that created the window. How do you create a window in one thread and cause another thread to receive that windo开发者_如何学编程w's messages? I have seen the PostThreadMessage function but I believe that it also requires for the thread that created the window to listen for messages, which is exactly the thing I'm trying to avoid, so that function is not what I need.
This seems like it would be a common question and I have spent quite a bit of time Googling for an answer, but I can't find one.
How do you create a window in one thread and cause another thread to receive that window's messages?
Simple answer ... you don't. Create the window on the thread you want to process its messages. If this is not possible then you need to re-think your approach.
The Windows message pump is really just a while
loop that picks messages off a queue using PeekMessage()
and call's your windows WndProc function. There's a little more to it than that, but that's the basic operation.
As such, whatever thread the while
loop runs in is the one and only thread your windows can "run" in. This is how every windows application I have ever seen is built.
However I have thought in the past that given a good deal of effort, it should be possible to construct a windows app with windows in multiple threads. I don't have any code to show you because it's been a long time since I thought about this, but there were two approaches I considered:
Keep one message pump in the main thread. But modify the message pump code so that in the
while
it dispatches messages to worker threads usingQueueUserAPC
based on the thread that particularHWND
is running in. A lookup map would be required for this, which can be computationally expensive.Create a whole new message pump in a worker thread. You would have to write all the
while
code, but this is simple enough, and Petzold's classic book will give you all the tools you need to do this.
Note that this approach makes no sense from an architectural point of view for any application I can think of. You simply don't need windows to run in multiple threads if you construct your app reasonably. Window handling happens in one thread, operations happen in another (or many). However, I have though this was an interesting research area, and that's what led me down this path. Long story short, I'm virtually certain you don't need to do this and shouldn't do this -- but this might be how you would do it.
It's not possible. Each window belongs to the thread that created it, and that ownership cannot be transferred.
It's not a matter of putting your message pump in another thread. Each thread has its own message queue. When you send or post a message to a window, the OS checks which thread owns that window and directs the message to that thread's message queue. Threads cannot read any message queue but their own, so you cannot have a thread process the messages of another thread's windows.
You could re-dispatch messages to another thread, as in the first idea in John's answer, but as a general-purpose message handler, that will become more complicated than it's worth. Many messages are meant to modify the state of the window, but you can't modify the state except from the window's own thread. Some messages are sent with the intention of getting a meaningful return value, but you can't know what to return until the message has been processed, so you'd have to block, waiting for the worker thread to process the message.
You'd be better off identifying the small set of messages that really can be off-loaded to a worker thread and handling them specially. Once you do that, you won't really have a window whose messages are handled in a different thread; you'll just have an ordinary worker thread, and it will be much less confusing to reason about.
If there are messages being sent to your window that require a lot of time to process, but the sender either doesn't need to know the result or you know the result before you finish the processing, then you can give an early response by calling ReplyMessage
. That lets the sending thread continue running while your window's thread does additional work.
You can see if AttachThreadInput works for you - it lets you handle messages from other threads.
This is really not that common of a question, because you almost always handle a windows' message in the thread where it was created. See Goz' answer; I agree.
Note that you will gain nothing from putting message processing in another thread. Don't break up GUI tasks into multiple threads, break up processing / background tasks into threads.
see this:
msdn:http://msdn.microsoft.com/en-us/library/ms644946(v=vs.85).aspx
The thread to which the message is posted must have created a message queue, or else the call to PostThreadMessage fails. Use the following method to handle this situation.
1.Create an event object, then create the thread.
2.Use the WaitForSingleObject function to wait for the event to be set to the signaled state before calling PostThreadMessage.
3.In the thread to which the message will be posted, call PeekMessage as shown here to force the system to create the message queue.
PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE)
4.Set the event, to indicate that the thread is ready to receive posted messages.
精彩评论