Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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 window'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.

like image 288
Epro Avatar asked Dec 03 '10 16:12

Epro


People also ask

What is message loop for a thread?

An event loop, or sometimes called a message loop, is a thread that waits for and dispatches incoming events. The thread blocks waiting for requests to arrive and then dispatches the event to an event handler function. A message queue is typically used by the loop to hold incoming messages.

What is the difference between GetMessage () and DispatchMessage () function?

GetMessage pulls the WM_LBUTTONDOWN message from the queue and fills in the MSG structure. Your program calls the TranslateMessage and DispatchMessage functions. Inside DispatchMessage, the operating system calls your window procedure. Your window procedure can either respond to the message or ignore it.

What is message loop in MFC?

In an application developed with MFC, the main message loop in the CWinThread class contains a message loop that calls the PeekMessage Win32 API. This loop also calls the OnIdle member function of CWinThread between messages. An application can process messages in this idle time by overriding the OnIdle function.

What is the difference between GetMessage and PeekMessage?

The main difference between the two functions is that GetMessage does not return until a message matching the filter criteria is placed in the queue, whereas PeekMessage returns immediately regardless of whether a message is in the queue.


3 Answers

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.

like image 56
Goz Avatar answered Oct 18 '22 21:10

Goz


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.

like image 42
Rob Kennedy Avatar answered Oct 18 '22 22:10

Rob Kennedy


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:

  1. 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 using QueueUserAPC based on the thread that particular HWND is running in. A lookup map would be required for this, which can be computationally expensive.

  2. 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.

like image 45
John Dibling Avatar answered Oct 18 '22 22:10

John Dibling