And that the entry in the MessageMap is:
ON_MESSAGE(UWM_TEST, OnNewTest)
And the definition of UWM_TEST is:
#define UWM_TEST (WM_USER + 1)
(although I read on Joe's site it should be WM_APP + __ ) -- just wanted to
keep this as close to the stuff already programed though.
Anything wrong in these areas that would be causing the behavior?
Thanks again,
Rob
This is known and documented behavior for PostThreadMessage, which should
never be used to post a message to a thread if the thread has any visible UI
components. See the MSDN documentation for PostThreadMessage, at
http://msdn2.microsoft.com/en-us/library/ms644946.aspx , which contains the
following text:
"Messages sent by PostThreadMessage are not associated with a window. As a
general rule, messages that are not associated with a window cannot be
dispatched by the DispatchMessage function. Therefore, if the recipient
thread is in a modal loop (as used by MessageBox or DialogBox), the messages
will be lost. To intercept thread messages while in a modal loop, use a
thread-specific hook."
Your thread will also be in a modal loop if the user is doing something very
simple, like dragging the application's window around on the desktop, or
re-sizing it. Try dragging/resizing your simple MDI example program, and
see if messages are lost.
See also explanations that abound on the web, and are similar to this one:
"Don't Use the Win32 API PostThreadMessage() to Post Messages to UI Threads"
at http://www.devx.com/tips/Tip/14720
Hello programmers!
Question - I have been battling this for 2 days now:
Why are some of my messages ignored or lost when I do a PostThreadMessage()
from a worker thread to my CWinApp derived class?
(I just made a simple MDI application from the new application wizard and am
trying to post messages to the CWinApp class that is generates)
My behavior explained:
The simple sample app I made works fine. I can execute the following line
of code from a worker thread:
AfxGetApp()->PostThreadMessage ( UWM_TEST, 5, 0 );
... And catch it in my CWinApp like this:
LRESULT CTestMessagePassingApp::OnNewTest(WPARAM wParam, LPARAM lParam)
{
...
}
It never fails. However, when I go to my larger project and implement
this, it works about 98% of the time. But sometimes my worker thread will
post the message and the CWinApp class never receives it! (or chooses to
discard it).
I have read article http://support.microsoft.com/kb/142415 and have tried
overriding PreTranslateMessage but that is still causing the same behavior
before I overrode it -- the CWinApp still sometimes misses this message.
I read Joe's article about safe message passing (good article):
http://www.flounder.com/iocompletion.htm
But cannot figure out how that works to pass messages directly to the
CWinApp thread (any suggestions if you are out there Joe?).
The app I am working on is huge and so heavily implemented at the CWinApp
level (instead at the MainFrm or other child window level) that I kinda have
to stay in the realm of getting messages to the CWinApp derived class.
Any suggestions?
Thanks,
Rob
Rob,
PostThreadMessage posts a message to a thread with no specific window.
To get the message to your handler it relies on your application's
message loop getting called. In some circumstances (such as when
operating a menu, displaying a message box or true modal dialog box)
your application's message loop is bypassed for generic ones inside
Windows. This message loop doesn't know what to do with your message,
so it gets discarded.
The best solution to this situation is to use PostMessage to post the
message to a specific window.
Dave
You can PostMessage to any window created in the main thread. CMainFrame is
a good choice but any window will work.
The message handler in the window can simply use AfxGetApp() to get a
pointer to the CWinApp. That pointer can be used to call an app function.
--
Scott McPhillips [VC++ MVP]
Thank you for posting Michael. This is starting to make sense. So on that
"David Lowndes" wrote:
Dave, Thank you for your reply! Can you help me with the last comment in
your post about using PostMessage to another window? As I was replying to
Michael above, I was asking how this is done and how that window I would be
posting to would know how to in turn call or invoke a function back in the
CWinApp class.
I think I am seeing a design flaw where not much should be implemented in
the CWinApp derived class, but at a different level like in the CMainFrame
class...
Thanks!
Rob
"Scott McPhillips [MVP]" wrote:
Hello Scott. Thank you for replying!
So you are saying that I execute a PostMessage() in a worker thread. Then I
catch that message in CMainFrame. Then from CMainFrame I use AfxGetApp() to
execute something back in the CWinApp based class?
I guess that makes sense. So then I would assume that you can call
AfxGetApp()->MyFunctionInTheCWinApp().... but when I use AfxGetApp()->, the
function is not listed -- just the functions listed in the base class
CWinApp. Is there a way to get at my custom functions in that level from
CMainFramer?
Maybe I am not supposed to have any new functions in my CWinApp based class
that are accessible from the outside, but rather just internal helper
functions?
I think I am missing the boat somewhere here.
Thank you very much for your help!
Rob
Rob,
You'd probably find it easiest to post the message to your
application's top level main frame window, and then from there you
could (if you really needed to) call AfxGetApp to gain access to your
application object and call a public method of that class.
>I think I am seeing a design flaw where not much should be implemented in
>the CWinApp derived class, but at a different level like in the CMainFrame
>class...
In this situation (where you need the window, it may be optimal to
have that functionality in the main frame window rather than the
application.
Dave
"David Lowndes" wrote:
Sounds good. I am not sure why AfxGetApp()-> is not pulling up my custom
functions back in the CWinApp class, but I don't see why we couldn't just
migrate everything from the CWinApp class up to the CMainFrame class as you
suggest.
If I did somehow figure out the first way (getting AfxGetApp()-> to pull up
my and list my custom functions), is that an ok/safe way of calling them?
-- cause then minimal change would be needed -- I would just be using
CMainFrame to route my messages.
Thanks again for replying!
Rob
You'll need to cast it to your specific derived application class.
>If I did somehow figure out the first way (getting AfxGetApp()-> to pull up
>my and list my custom functions), is that an ok/safe way of calling them?
It should be.
Dave
AfxGetApp() returns a CWinApp pointer. To call your added functions you can
cast it to your own app class.
CYourApp* p = (CYourApp*)AfxGetApp();
p->YourAppFunction();
But this is ugly and not really recommended. The more elegant way is to add
an extern declaration in yourapp.h
extern CYourApp theApp;
Then to call your functions you can simply do:
theApp.YourAppFunction();
For this you need to remember a bit about the C++ language itself, besides
Microsoft's frameworks. AfxGetApp() returns a pointer of a type that
Microsoft knew about. You know the type of your actual application's class,
which is derived from Microsoft's base class. So cast this pointer to your
type. Then you can call your method.
I supply a property in the thread which returns the CWnd and clients post
using this.
I reckon that this is a bug in MFC, but some call it a feature.
It is erroneous to do so. Don't do it.
joe
On Thu, 4 Oct 2007 12:51:02 -0700, RobKinney1 <mydigital...@gmail.com.NOSPAMPLEASE>
wrote:
Joseph M. Newcomer [MVP]
email: newc...@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
On Thu, 4 Oct 2007 16:43:20 -0400, "Scott McPhillips [MVP]" <org-dot-mvps-at-scottmcp>
wrote:
On Thu, 4 Oct 2007 14:19:01 -0700, RobKinney1 <mydigital...@gmail.com.NOSPAMPLEASE>
wrote:
>
>
>"David Lowndes" wrote:
>
>> >Dave, Thank you for your reply! Can you help me with the last comment in
>> >your post about using PostMessage to another window? As I was replying to
>> >Michael above, I was asking how this is done and how that window I would be
>> >posting to would know how to in turn call or invoke a function back in the
>> >CWinApp class.
>>
>> Rob,
>>
>> You'd probably find it easiest to post the message to your
>> application's top level main frame window, and then from there you
>> could (if you really needed to) call AfxGetApp to gain access to your
>> application object and call a public method of that class.
>>
>> >I think I am seeing a design flaw where not much should be implemented in
>> >the CWinApp derived class, but at a different level like in the CMainFrame
>> >class...
>>
>> In this situation (where you need the window, it may be optimal to
>> have that functionality in the main frame window rather than the
>> application.
>>
>> Dave
>>
>
>Sounds good. I am not sure why AfxGetApp()-> is not pulling up my custom
>functions back in the CWinApp class,
****
Because it is not supposed to! AfxGetApp is specified as returning a CWinApp*, which it
does. Your functions are not part of the class CWinApp*. This is an elementary C++
language issue.
****
>but I don't see why we couldn't just
>migrate everything from the CWinApp class up to the CMainFrame class as you
>suggest.
****
I make it a policy to NEVER use my CWinApp-derived class outside its implementation file.
Since I have not found a reason to use it in years, I question why anyone (particularly
Microsoft) thinks it is necessary (the first thing I do with code these days is rip out
every #include "whatever.h" for whatever.h being my CWinApp-derived class definition.
Either the #include disappears entirely, or it is replaced by #include "resource.h" which
is all that is needed. There is no need to use the CWinApp class outside the CWinApp
implementration. It's called "modular design". I also don't use the CMainFrame class
outside the CMainFrame, and the CMainFrame class NEVER needs to know about any view
windows that are under it, or documents. I don't even use GetActiveView or
GetActiveDocument if I need a method from my classes; if I can't do it with the CView or
CDocument class methods, it doesn't belong.
*****
>
>If I did somehow figure out the first way (getting AfxGetApp()-> to pull up
>my and list my custom functions), is that an ok/safe way of calling them?
>-- cause then minimal change would be needed -- I would just be using
>CMainFrame to route my messages.
****
Again, this is basic C++ language knowledge, but you shouldn't be doing it. I gave you
the answer earlier, and it is always a sure sign that there is a design problem.
joe
****
>
>Thanks again for replying!
>
>Rob
"Scott McPhillips [MVP]" wrote:
> AfxGetApp() returns a CWinApp pointer. To call your added functions you can
> cast it to your own app class.
>
> CYourApp* p = (CYourApp*)AfxGetApp();
> p->YourAppFunction();
>
> But this is ugly and not really recommended. The more elegant way is to add
> an extern declaration in yourapp.h
>
> extern CYourApp theApp;
>
> Then to call your functions you can simply do:
>
> theApp.YourAppFunction();
>
> --
> Scott McPhillips [VC++ MVP]
Thanks Scott! This worked great. I am now using this method instead of the
PostThreadMessage!
Rob
"Joseph M. Newcomer" wrote:
> Because you cannot PostThreadMessage to any class in the main GUI thread. It doesn't
> work. Read the documentation for PostThreadMessage. It explains why it won't work.
>
> It is erroneous to do so. Don't do it.
> joe
Thank you Joe for your commenting throughout this thread. :~]
Yes, I think this could use a redesign sometime to help fix all these
issues. I wasn't aware of a lot of these until you pointed them out.
This will be a good reference thread for me later!
Thanks,
Rob