Link to home
Start Free TrialLog in
Avatar of IFKMild
IFKMild

asked on

How to communicate with a UI CWinThread?

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?
SOLUTION
Avatar of AndyAinscow
AndyAinscow
Flag of Switzerland image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of IFKMild
IFKMild

ASKER

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!
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
<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).
Avatar of IFKMild

ASKER

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!
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.
Avatar of IFKMild

ASKER

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.
Does the window close?  Put a TRACE statement into it's destructor for example.
why do not you use SendMessage for WM_CLOSE
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);
}
Avatar of IFKMild

ASKER

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!