How to communicate with a UI CWinThread?

Posted on 2004-04-20
Last Modified: 2013-11-20
In a project I'm working in we have been using UI CWinThreads. We have a number of threads that each run a window. To communicate with the threads we have used PostThreadMessage. For example, to kill a thread we have used PostThreadMessage(WM_QUIT,0,0) and waited for the thread to signal proper termination.

I was shocked to find the following article:;en-us;183116

I guess PostThreadMessage can not be used safely at all with UI threads! If the thread's window for some reason enters a modal state (e.g. by displaying a modal message box or even by being moved or resized), then these messages are simply lost! I'm still stunned as to how the documentation is not VERY clear on this potentially HUGE drawback...

The MS recommendation is to create a "dummy window" and to use PostMessage to that window instead, but unfortunately I do not understand exactly how to do this. Specifically, I do not understand how to handle termination. How do I make the thread terminate by sending a message to the thread's window?

To my surprise I have not found much info on the topic. Has anybody got a clue on how to approach the problem?
Question by:IFKMild
  • 4
  • 4
  • 3
  • +1
LVL 44

Assisted Solution

AndyAinscow earned 250 total points
ID: 10875707
Each of your threads owns/runs a window.  If I understand it correctly the recommendation is to post a message to a window owned by the thread rather than PostThreadMessage.  Now your thread already has a window so no requirement for a 'dummy window', you could use the window associated with the thread as the recipient of the message.  This window would be set to close after the modal state terminates and then your thread is terminated as part of the closure procedure.
The is a GetWindowThreadID that returns the ID of the thread that created the window.


Accepted Solution

vijay_visana earned 250 total points
ID: 10875823
This is bit tricky but not much difficult. I have implemented it in my code in your thread create a dummy window(do not show it) and return handle to this window to parent thread thread or put it in some global vriable now you can communicate with this thread using postmessage to that dummy window and your message will not be droped as secondary message loop (that is started due to call to do modal from your thread) dispatch it to windows proc of your dummy windows and threre you can handle it.

Author Comment

ID: 10880540
Ok, I think I understand what you are getting at, but unfortunately I'm still somewhat confused. I can send messages to my "dummy" window without any problem. What I'm wondering now is what the best way would be for this window to communicate with the thread?

Right now I'm doing something along the lines of:
PostMessage(iDummyWindow->GetSafeHwnd(),THREAD_MESSAGE_ID, wParam,lParam)
from the caller (where I originally tried to use PostThreadMessage).
In the dummy window I currently have a message map and catch the message using ON_MESSAGE(THREAD_MESSAGE_ID,threadMessageHandler)

I'm not really happy with the above setup, but if this is the only way to go, then so be it. Or have I misunderstood something?

My next question (assuming I have not messed things up so far) is what I should do in "threadMessageHandler". Should I identify the message sent to me (by an id sent in wParam) and use that information to call functions in the thread directly, or is there a better way? (Please tell me that there is a better way!) :-)

I would like to add that as we currently have a CWinThread-derived class called InterfaceThread used throughout the application, I'd like as much of the work as possible to be done in that class, so that I do not have to implement functionality in all subclasses of InterfaceThread.

Thank's for helping out! By the way, I'm still quite amazed that PostThreadMessage handles the way it does!
Enterprise Mobility and BYOD For Dummies

Like “For Dummies” books, you can read this in whatever order you choose and learn about mobility and BYOD; and how to put a competitive mobile infrastructure in place. Developed for SMBs and large enterprises alike, you will find helpful use cases, planning, and implementation.


Expert Comment

ID: 10885662
Sometime we hit the wall (design or mis-design by M$) and do away with it.

>>what I should do in "threadMessageHandler"
I think you better handle it in your dummy window's win proc.

LVL 44

Expert Comment

ID: 10885819
<I'm not really happy with the above setup, but if this is the only way to go, then so be it. Or have I misunderstood something?>

My understanding of this is that that is the way to go.  To write code that is pleasing and works is one thing.  To write code that works one is paid for.

<My next question (assuming I have not messed things up so far) is what I should do in "threadMessageHandler". Should I identify the message sent to me (by an id sent in wParam) and use that information to call functions in the thread directly, or is there a better way?>

That seems to be a sensible way to do things.  That should preserve as much of your original code as possible as the handlers were there originally, you are now calling them via one layer of abstraction (window message).

Author Comment

ID: 10897538
Ok. I'm getting closer to a solution. I wanted to keep things as transparent as possible for clients of my InterfaceThread class. Right now I have two possible solutions.

In the first solution I use PostMessage and send a message to the dummy window. The dummy window calls an overridable method in the thread class that actually handles the message.
The drawback as I see it with this solution is that a) you need to implement this overridable method in each subclass of InterfaceThread (not such a big deal really) sp you are not using the 'standard' message map, which makes clients of the class less portable and b) You lose the abillity to use both wParam and lParam as message parameters as you need to use one of them to identify the actual message.
I guess it would be possible for each subclass to have their own dummy window with its own message map to work around the latter problem though.

Another solution I have tried uses (and I hate to admit this) PreTranslateMessage in the dummy window and ProcessMessageFilter in the thread class. I read which led me to this solution. That way I can intercept the message and dispatch it via the thread's message map using DispatchThreadMessage. I admit that it is NOT a pretty solution, but on the other hand it seems to be working and is fully transparent to all clients of InterfaceThread.

However, for both solutions I still can not handle WM_QUIT properly. If I post a WM_QUIT message to my thread using any of these methods while moving the user interface window around (to put the thread into a modal state), I simply cannot terminate my thread in a nice way. Either it is shut down so hard the thread didn't know what hit it, or it does not shut down at all.

The only way I can accomplish proper thread termination is to post messages over and over again until an event is signalled, but I'm not sure I like that. Surely there must be a better way that I have overlooked? I really want to get things right in this case since the InterfaceThread class is quite fundamental to our application. I believe it is worthwhile to get it right!

So, in short, I still have not figured out how to terminate a thread while it is in a modal state. How would I go about it?

Sorry for the ranting folks!
LVL 44

Expert Comment

ID: 10897563
To your first comment.
Pass the WPARAM and LPARAM as aprameters to the function in the thread - you then retain that information.
Have a virtual function in your base thread that does a default response.

For terminating the thread in the modal state the window it owns needs to be closed.  So that should receive a WM_CLOSE message, process it then you kill the thread.

Author Comment

ID: 10897664
I see what you are saying on the parameter issue.

However, I'm more concerned about terminating the thread. I tried to do the following in the function being called from ProcessMessageFilter (which is run when in modal state):


This message just seems to disappear and the thread will not terminate.
LVL 44

Expert Comment

ID: 10897772
Does the window close?  Put a TRACE statement into it's destructor for example.

Expert Comment

ID: 10897908
why do not you use SendMessage for WM_CLOSE

Expert Comment

ID: 10982245
The way I forward ON_COMMAND UI messages to CWinThread objects is by overriding the OnCmdMsg function in CMainFrame, so that the OnCmdMsg function is called in my thread object:

BOOL CMainFrame::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo)
   // let the view have first crack at the command
   if (m_wndView.OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
      return TRUE;
   // Pass commands on to the thread as well
   if (m_pThread->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
      return TRUE;
   // otherwise, do default handling
   return CFrameWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);

Author Comment

ID: 11066834
Sorry for not commenting on this question for so long. I've been tied up in a bunch of other things (as always) here at work, and could not focus on this problem for a while.

When testing, the WM_CLOSE message sent to my dummy window didn't seem to get there for some strange reason (I really can't remember, it actually might have), but the problem is what I should have done with it. How would I've terminated the thread in a nice way? The only way to get it to exit the message handling loop in Run would be to somehow post WM_QUIT to it, and the thread is not listening to PostThreadMessage messages.
Also, I do not want to close the window until it exits it modal state, so I had to make sure that the message was not handled until that time.

The solution I mentioned above have been implemented and seem to work well. I have a dummy window in the thread, and it handles all the dispatching of thread messages. The interface to the InterfaceThread class is actually quite clean and easy to understand, even though the class in itself is a bit suspicous if you do not know about the problem. The solution has gone through initial testing with flying colors, so I believe it will work well.

I would like to mention that I came across another approach when trying to find information on this topic. Some people appearantly do not like their application to enter Run at all, so their entire programs run in InitInstance and they manage message handling in that function as well. When the program should terminate, they exit from InitInstance with a FALSE return value, so that Run never executes. I _really_ did not like that approach, but I thought it was worth mentioning.

I will split the points between vijay and Andy as I felt you really helped me get on the right track. Thanks!

Featured Post

DevOps Toolchain Recommendations

Read this Gartner Research Note and discover how your IT organization can automate and optimize DevOps processes using a toolchain architecture.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
viewing source code from eclipse 13 108
wait notify demo infinite loop 3 114
fix34  challenge 9 123
sumHeights2  challenge 7 107
Introduction: Load and Save to file, Document-View interaction inside the SDI. Continuing from the second article about sudoku.   Open the project in visual studio. From the class view select CSudokuDoc and double click to open the header …
Introduction: Hints for the grid button.  Nested classes, templated collections.  Squash that darned bug! Continuing from the sixth article about sudoku.   Open the project in visual studio. First we will finish with the SUD_SETVALUE messa…
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
In a recent question ( here at Experts Exchange, a member asked how to add page numbers to a PDF file using Adobe Acrobat XI Pro. This short video Micro Tutorial sh…

832 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question