Solved

PostThreadMessage vs PostMessage

Posted on 2001-09-03
33
1,861 Views
Last Modified: 2008-03-17
hi,
I have a problem :
I am using a dll that I wrote that performs some async task.
I am using this dll from an mfc app.
on the mfc app I create a UI thread and overwrite the preTranslateMessage function to handle the event of the dll finishing his task and then i provoke a function from a this pointer given to the UI thread.
when I create the dll I pass to it the threadID of the waiting thread, and when the task is completed in the dll the dll uses PostThreadMessage with the given thread id.

the messages passes just fine and everything was working ok until I inserted a simple .ocx component (just a simple better looking slider) and when the dll signal the mfc app waiting UIThread I provoke a function from the ocx. (using standard vc invokeHelper)
when I do that, I get an Access Violation and the app crash.
if I use functions of the ocx not when the message comes from the dll it works fine. (before or after a message is sent but not as response to the message, then it crash)
While I was exploring the problem I was able to make it work like that (I don't like this solution):
I pass to the dll the mfc app m_hWnd, I overwrite the PreTranslateMessage of the dialog (of the app)20.and I am using in the dll the PostMessage with the Handle and the message.
when I use it like that the message passes and the .ocx component doesn't crash, but OOP speaking there is NO reason what so ever that the dll will hold a handle to the dialog of the app, and I don't want to overwrite the PreTranslateMessage of the dialog, it got better things to do, I want my own thread handling the messages from the dll.
does anyone knows why this strange phenomenon happens ?
what does PostMessage(...) and PostThreadMessage(....) differ all that much ?
what does the .ocx writen in VB got to do with any of it ???
why does evil people exist ? (just kidding I know the answer to that one....(-:)

thanks in advance.

Snow_Master
0
Comment
Question by:snow_master
  • 12
  • 8
  • 7
  • +2
33 Comments
 
LVL 5

Expert Comment

by:ekc
Comment Utility
The difference between the PostMessage() and the other one is that the PostMessage() is sending a message to the window, and PostThreadMessage() - to the thread. That is obvious.
Now, in your case... I suppose you have put the OCX on the dialog (to which you are sending a message using PostMessage() in your second, "ugly" solution). This means that you invoke the OCX's InvokeHelper() from its parent window - your main app window. This works fine...
In the first case, you were sending the PostThreadMessage() to your UI thread, which (I suppose) is the different from the main UI thread of your app. It worked fine until you have tried to access the OCX from this thread. I suspect you might have error here... How your UI thread knows about the main dialog's OCX? This could provoke the access violation, because you can't easily share the MFC object between the threads... You could resolve this problem (if it is a problem actually, I'm not sure) by detaching your IDispatch in the main UI thread and attaching it in the other one (DetachDispatch() and AttachDispatch() functions) - this is the safe way of sharing the MFC object between the threads. Of course, you have to do the same, upon "returning" the IDispatch to the main UI thread.
0
 
LVL 5

Expert Comment

by:ekc
Comment Utility
I forgot to say that you actually pass IDispath ptr (LPDISPATCH) to your UI thread. Take a look to mentioned COleDispatchDriver's functions and it should be clear enuogh.
Good luck!

BTW... Why do evil people exist? You said you knew it?
0
 

Author Comment

by:snow_master
Comment Utility
>>How your UI thread knows about the main
>>dialog's OCX?
the UIThread gets in his constructor a pointer (the "this" of the dialog) and provoke a public function of the dialog when the currect message is translated. that function provokes the .ocx function (the .ocx function is not invoked directly from the UIThread)
0
 

Author Comment

by:snow_master
Comment Utility
evil people exists because if they where only good people no one could know that they are good because you wouldn't know what evil people are....(I just made that up but it makes sense, no ?)
0
 

Author Comment

by:snow_master
Comment Utility
evil people exists because if they where only good people no one could know that they are good because you wouldn't know what evil people are....(I just made that up but it makes sense, no ?)
0
 
LVL 5

Expert Comment

by:ekc
Comment Utility
>>How your UI thread knows about the main
>>dialog's OCX?
the UIThread gets in his constructor a pointer (the "this" of the dialog) and provoke a public function
of the dialog when the currect message is translated. that function provokes the .ocx function (the
.ocx function is not invoked directly from the UIThread)

It doesn't matter it is not "directly" invoked from the thread, actually it IS invoked from the outer thread from its own, and now I'm pretty sure that is the problem.
You can resolve it as I suggested you before.
It is out of the question's scope, but I'm not sure this is very good design decision eighter. Why should the outer thread know inner structure of your main dialog and even access it directly?
The better (and easier, since it is compatible with your old one) solution could be to keep with the PostThreadMessage() communication in the same way as before, only that know to send the message to the app's main thread and process the OCX function invocation from there, safely... The outer thread now doesn't have idea of the dialog, OCX, only knows its father ThreadID which is ok from the point of view of the OO... What do you think?
0
 
LVL 49

Expert Comment

by:DanRollins
Comment Utility
>>the UIThread gets in his constructor a pointer (the "this" of the dialog) and provoke a public function...

You can not (must not) pass a CWnd* from one thread to another.  That is because MFC internally makes a map of HWNDs to CWnd* s per thread.  That thread's map does not have the other threads HWND in its list, presto crash (normally an ASSERT in debug version).

To prevent this, you must not use the public functions of CDialog-derived objects from other threads.  There are many options to avoid this problem.  Here are two I have used successfully:

*) Post a message to the HWND (using ::PostMessage(HWND,...) if the CDialog.  You may need to provide a handler for that message in the CDialog -- depending upon what message you post.

*) Use a timer.  For instance, to update a progress control, my CDialog has a public DATA member m_nPctDone.  The external DLL can access the data member to update it periodically.  Then the CDialog uses an OnTimer handler to actually update the on-screen progress control to set it to the most recent setting in m_PctDone.  That way, all of the UI updating takes place on the UI thread's timeslice and not on the worker thread's timesplce.

-- Dan
0
 

Author Comment

by:snow_master
Comment Utility
ekc :
>>it IS invoked from the outer thread from its own,
Could you please clarify, what do you mean outer thread ?

if that is the problem, your solution isn't good for me because the .ocx is used all the time from the dialog, I can't Detach it from the dialog, and it's also wrong OO, the thread that is waiting for the message, should only wait for the message (like a LISTENER in Java) and notify the dialog when it happens, as a response the dialog perform allot of actions including provoking the .ocx function.

Dan :
I am trying to avoid your first solution (read my question)
And your second solution is busy waiting with a delay...(bad software solution, time consuming)

0
 

Author Comment

by:snow_master
Comment Utility
bare in mind i need to pass data from the message that came from the dll to the main dialog, not just notify the event.
0
 
LVL 9

Expert Comment

by:ShaunWilde
Comment Utility
> bare in mind i need to pass data from the message that came from the dll to the main dialog, not just notify the event

then create a sructure (class) to hold it and pass it via the lParam

pData = new CMyPassedData;
PostMessage(hWnd,MM_MESSAGE,0,(LPARAM)pData);

PostThreadMessage(dwThreadId,MM_MESSAGE,0,(LPARAM)pData);

0
 

Author Comment

by:snow_master
Comment Utility
Shaun :
that's what i am doing from the dll to the listner thread but how do i pass it to the dialog from the listener thread without overwriting the preTranslateMessage of the dialog and still won't get the access violation ? thats the problem....
0
 
LVL 5

Expert Comment

by:ekc
Comment Utility
> ekc :
> >>it IS invoked from the outer thread from its own,
> Could you please clarify, what do you mean outer thread ?

Of course. By the outer thread I actually ment your second UI thread. If it has the ptr to the dialog (which itself runs in the main app UI thread) and invoke any of its functions, it doesn't matters which thread actually created the dlg, but the fact which thread INVOKED function. In your case, you invoked dialog's (and OCX's) function from your second thread, which causes the crash.

> if that is the problem, your solution isn't good for me because the .ocx is used all the time from the
dialog, I can't Detach it from the dialog,

I didn't suggest you to remove the OCX from the dialog, of course you need it, it is your UI element. You need to detach the LPDISPATCH ptr (actual pointer to your OCX, encapsulated by the MFC class COleDispatchDriver) from its COleDispatchDriver just before the other thread accesses it, and attach it in the second thread. After "external" processing, just detach it from that thread and attach it back to your main thread. You need some sync mechanisms an everything, because of that this isn't very good solution.

> bare in mind i need to pass data from the message that came from the dll to the main dialog, not just
notify the event.

ShaunWilde gave you the solution. That way, you can send anything you want. Thread messages are very good comm mechanism because it provide the syncronism, is fast and relies on the OS very low.
Just send the message to main thread using PostThreadMessage() pointing to some defined structure or class and forget about calling OCX from outside world.

0
 
LVL 49

Expert Comment

by:DanRollins
Comment Utility
>> ... (read my question)
I did, at least four times.

>> , but OOP speaking there is NO reason what so ever that
>> the dll will hold a handle to the dialog of the app,

The DLL *will* have some connection to the app, right?  /Otherwise how does it tell the app to update the UI?  So whether it is a pointer to a CDialog-derived class or an HWND, what is the difference?

For OOP purity, you can have a member function in the app called, say UpdateMySlider().  That function hides the details of the implementation.  In that function you can do whatever you need to do to avoid the "wrong thread" problem.  So how do you avoid this problem?  Have the CDialog code post a message to itself.  Or have it set a flag so that on the next message that it processes it will take some action.  Or use a timer as I've suggested -- users will not notice a delay of 250ms (1/4 of a second) for a screen element to be updated.

>> and I don't want to overwrite the PreTranslateMessage of the dialog,

Why not?  Anyway, there are lots of other mechanisms for processing messages.  For instance, make it a WM_COMMAND message and handle it just as you do with button clicks, etc.

-- Dan

P.S.  ekc's suggestion of detach/reattach sounds complicated, but could be an interesting alternative.  I would be interested in seeing this in action (a link to an example of the technique?)
0
 

Author Comment

by:snow_master
Comment Utility
ekc :
>Of course. By the outer thread I actually ment your >second UI thread. If it has the ptr to the dialog
>(which itself runs in the main app UI thread) and invoke >any of its functions, it doesn't matters which
>thread actually created the dlg, but the fact which >thread INVOKED function. In your case, you invoked
>dialog's (and OCX's) function from your second thread, >which causes the crash.

I checked on debug all the addresses and references and they are the same!!(i compared a regular call from the dialog and the call to the dialog from the ui thread), furthermore I engaged a vc standard slider (not my vb .ocx slider) and it works fine(the call from the ui thread doesn't fail) !!!
I still don't understand why the crash is happening.


Dan :
>The DLL *will* have some connection to the app, >right?  /Otherwise how does it tell the app to update
>the UI?  So whether it is a pointer to a CDialog-derived >class or an HWND, what is the difference?

the design was to pass the dll ONLY the threadID of the listener thread, and the dll will use PostThreadMessage, by that i will get encapsulation, because the dll will be able to notify the app of the event but won't have access to the app.
 
>Why not?  Anyway, there are lots of other mechanisms for >processing messages.  For instance, make it
>a WM_COMMAND message and handle it just as you do with >button clicks, etc.

to simplify the question I didn't explained the full design actually not the dialog is responsible for this event but another class which is the AppManeger, allot of very complicated calculation is being done when the event happens, and the slider update in the dialog is a simple side effect, therefore the class that should be notified of the event isn't the dialog but the AppManeger that doesn't have a Message Queue and therefore doesn't have a PreTranslateMessage function to overwrite.
ekc, this is also the reason why the attach detach solution isn't good for me, it might solve the slider issue but at the wrong place (the UIThread) and as I explained the slider is a simple side effect of the event.
 
0
 
LVL 5

Expert Comment

by:ekc
Comment Utility
> I checked on debug all the addresses and references and they are the same!!(i compared a regular call
from the dialog and the call to the dialog from the ui thread), furthermore I engaged a vc standard
slider (not my vb .ocx slider) and it works fine(the call from the ui thread doesn't fail) !!!
I still don't understand why the crash is happening.

snow_master,
The threads are sharing the SAME process space, so they share same code and data local to that process. That's why the addresses are the same, you should have not expected something else. The fact is from which thread a object of function (SAME object or function!) is accessed.
To be accessed from different threads simultaneosly, the object (in this case OCX or VC slider) should be, what is called "thread-safe". This means to have implemented protection code assuring that it won't be possible for two threads to try to access its data in the same time and make some inconsitency. MFC classes ARE NOT thread-safe by default, it is YOUR responsability to make them thread-safe. It is very possible that VC standard slider is thread-safe, because it is not MFC object, it comes from the lower level API...
I recommend you some readings on the topic of thread mechanismls, thread syncronisation and sharing data among threads, especially MFC data. That should make it clearer to you...
0
 
LVL 9

Expert Comment

by:ShaunWilde
Comment Utility
Okay lets see if I can get this in my head straight

you have a VB control that send events (COM) to the hosting dialog but when it does it all goes horribly wrong?

have you got an AFX_MANAGE_STATE macro in your handler  for the ocx event?
0
Free Trending Threat Insights Every Day

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

 
LVL 49

Expert Comment

by:DanRollins
Comment Utility
The DLL is given a threadID.  It uses PostThreadMessage( thdID...) to signal an event to that thread.

So what's the problem?  In the handler for that thread message, choose one of the options I described before.  The important thing is to be running your UI thread in the dialog when you cause the slider (or any other UI activity) to occur.

I agree with Shaun that the problem migh disappear if you use the AFX_MANAGE_STATE macro.

-- Dan
0
 

Author Comment

by:snow_master
Comment Utility
Shaun :
the process is :
1. an event from a hardware device happens in a c++ DLL
2. this DLL sends a PostThreadMessage to a CWinThread    Derived class with this class ThreadID.
3. the CWinThread derived class receives the message from the overwritten PreTranslateMessage, and provokes a public function of a generic base class called app manager from a pointer given in construction.
4. one of the things that this app manager function does is to call a public function of the app dialog named updateSliders.
5. the updateSliders of the dialog provokes a function of a VB .ocx Slider
6. BOOM access violation.

same thing but with vc standard slider works fine.
calls to the vb .ocx slider that aren't from the response to the event of the dll works fine.

where to put the AFX_MANAGE_STATE ?
to use AFX_MANAGE_STATE(AfxGetStaticModuleState( )) ?
0
 
LVL 9

Expert Comment

by:ShaunWilde
Comment Utility
I'd stick it in the handler for the message but...

is the CWinThread in (3) in a different thread to the dialog/control in (4,5) - if so you may be trying to access the control from the wrong thread. try posting a message from the thread to the dialog that then updates the sliders - could be COM related - eg the control (ocx) is in one STA and you are trying to access it from the wrong thread - VB isn't very thread safe

but if that doens't work I think we have had enough guessing - can you send a zip with source for what is happening (eg can you make a simple sample that shows what is happpening) - and we can try to run it on our machines and see what is going on - the event from the hardware device will have to be kicked of in another fashion (menu,button) - shaun_wilde@hotmail.com
0
 
LVL 49

Expert Comment

by:DanRollins
Comment Utility
From your description, it is quite clear that the call to the dialog function is taking place on the worker thread's timeslice.  You need to replace the direct call with a PostMessage() to the dialog.  Or modify how updateSliders() works so that *it* posts a message to the dialog.  

That way, when the dialog next gets a timeslice, it will get the message and take the action -- on the UI thread that created the OCX.  Very simple really.

If you don't understand the need to do this, then there is every chance that your worker threads are calling other functions in the dialog and that some other part of the UI will eventually break.  It is very important to decouple the worker threads from the UI functions.

Do you need help in setting up to handle a user-defined posted message?

-- Dan--
0
 
LVL 9

Expert Comment

by:ShaunWilde
Comment Utility
It seems that ekc,DanRollins and I are all in agreement :)
0
 
LVL 49

Expert Comment

by:DanRollins
Comment Utility
Yikes! Is it too late to change my opinion? :)

-- Dan
0
 

Author Comment

by:snow_master
Comment Utility
o.k you guys :
first of all thank you for your time.
second, as I mentioned in my first post I found a way to make it work using postMessage from the dll to the dialog but I need to give the dll the h_Wnd of the dialog to do so which I didn't really liked, but since all of you are telling me that I cant provoke methods of UI object that relates to UI components from a different thread on a different time slice, I will go back to the PostMessage solution form the dll to the dialog.
(the listener thread that will get the PostThreadMessage and he will give the exact PostMessage to the dialog is just overdoing the same thing...)
I don't really know whom to give the points too, since none of you gave me the solution i wanted, but all of you helped me understand the problem more, so please tell me who you think should receive the points and I will give it to him.
thanks again.

Snow_Master
0
 
LVL 9

Expert Comment

by:ShaunWilde
Comment Utility
you can always split ask the moderator in the community support board on how you would like the split done
0
 

Author Comment

by:snow_master
Comment Utility
how do i do that ? who is the moderator ?
0
 
LVL 9

Expert Comment

by:ShaunWilde
Comment Utility
just post a message - with a topic like 'Point Split required' and then leave a message with the link to this question and how you would like the point split and they will do the deed
0
 
LVL 49

Expert Comment

by:DanRollins
Comment Utility
One typically posts such "Please split points" Qs on the community support topic:

http://www.experts-exchange.com/jsp/qList.jsp?ta=commspt

-- Dan
0
 
LVL 49

Expert Comment

by:DanRollins
Comment Utility
hi snow_master,
Do you have any additional questions?  Do any comments need clarification?

-- Dan
0
 

Author Comment

by:snow_master
Comment Utility
Dan,
I posted a split points question request to all of you since non of you really gave me a solution to my problem, but all of you helped me understand it better.
I can't say I completely understand why the dialog cant share .ocx to another thread, but I come from java where the system is a different, and I had spent too much time on that issue already.(deadline, you know....(-:)
any how
thanks any way.
and I hope the MFC crap will be over when VC.Net will be released...
0
 
LVL 9

Expert Comment

by:ShaunWilde
Comment Utility
> I can't say I completely understand why the dialog cant share .ocx to another thread

because the ocx isn't thread safe as VB isn't thread safe - why? ask Microsoft and they'll say - 'It's by design'
0
 
LVL 49

Accepted Solution

by:
DanRollins earned 66 total points
Comment Utility
I, for one, have no record of receiving points for helping with this Q.  If you want to split points, you must nake a post here:

  http://www.experts-exchange.com/jsp/qList.jsp?ta=commspt

Be sure to provide a link to this Q (20177910) and to describe how you wish to split the points.  Also mention the Q that you posted in the C++ section and ask to have it deleted.

-- Dan
0
 
LVL 2

Expert Comment

by:Lunchy
Comment Utility
0
 

Author Comment

by:snow_master
Comment Utility
Lunchy,
why you didn't gave any points to dan ?
i asked to split the points to 3 (ekc, shaun and dan)
Jonathan.
0

Featured Post

What Should I Do With This Threat Intelligence?

Are you wondering if you actually need threat intelligence? The answer is yes. We explain the basics for creating useful threat intelligence.

Join & Write a Comment

Often, when implementing a feature, you won't know how certain events should be handled at the point where they occur and you'd rather defer to the user of your function or class. For example, a XML parser will extract a tag from the source code, wh…
What is C++ STL?: STL stands for Standard Template Library and is a part of standard C++ libraries. It contains many useful data structures (containers) and algorithms, which can spare you a lot of the time. Today we will look at the STL Vector. …
The goal of the video will be to teach the user the concept of local variables and scope. An example of a locally defined variable will be given as well as an explanation of what scope is in C++. The local variable and concept of scope will be relat…
The viewer will learn additional member functions of the vector class. Specifically, the capacity and swap member functions will be introduced.

762 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

7 Experts available now in Live!

Get 1:1 Help Now