Solved

How to communicate with a UI CWinThread?

Posted on 2004-04-20
12
1,138 Views
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:
http://support.microsoft.com/default.aspx?scid=kb;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?
0
Comment
Question by:IFKMild
  • 4
  • 4
  • 3
  • +1
12 Comments
 
LVL 44

Assisted Solution

by:AndyAinscow
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.

0
 
LVL 7

Accepted Solution

by:
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.
0
 

Author Comment

by:IFKMild
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!
0
 
LVL 7

Expert Comment

by:vijay_visana
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.


Vijay
0
 
LVL 44

Expert Comment

by:AndyAinscow
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).
0
 

Author Comment

by:IFKMild
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 http://support.microsoft.com/default.aspx?kbid=126874 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!
0
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 
LVL 44

Expert Comment

by:AndyAinscow
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.
0
 

Author Comment

by:IFKMild
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):

PostMessage(m_pMainWnd->GetSafeHwnd(),WM_CLOSE,0,0);

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

Expert Comment

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

Expert Comment

by:vijay_visana
ID: 10897908
why do not you use SendMessage for WM_CLOSE
0
 

Expert Comment

by:carld98
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);
}
0
 

Author Comment

by:IFKMild
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!
0

Featured Post

Highfive Gives IT Their Time Back

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

Suggested Solutions

This is to be the first in a series of articles demonstrating the development of a complete windows based application using the MFC classes.  I’ll try to keep each article focused on one (or a couple) of the tasks that one may meet.   Introductio…
Exception Handling is in the core of any application that is able to dignify its name. In this article, I'll guide you through the process of writing a DRY (Don't Repeat Yourself) Exception Handling mechanism, using Aspect Oriented Programming.
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.
It is a freely distributed piece of software for such tasks as photo retouching, image composition and image authoring. It works on many operating systems, in many languages.

759 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

Need Help in Real-Time?

Connect with top rated Experts

20 Experts available now in Live!

Get 1:1 Help Now