Re: MFC - Cdialog::OnOK() in Thread
Well I'll have to dig through your Ariticle. For all the details
The worker function is as follows and it do seem to get started, but the button that it calls does a lot of work, and eventuall I get the Assertions:
Code:
UINT WorkerThreadProc( LPVOID Param ){
CFormHdrView *pCFV ;
pCFV = (CFormHdrView *)Param;
if(::gpCFVw_Hdr == NULL)::AfxMessageBox("Null Pointer");
pCFV->OnButtonTotlsRevs();
return TRUE;
}
That looks pretty light weight to me. I don't know if forcing the function Inline would help the thread cut further into my CFormView App with tons of CDialogs.
I guess when the manufacture of a product, which in this case is Microsoft, says the product is not intended to be used in a certain way, that pretty much draws the line. Accessing the GUI Objects from threads was "not the way the Objects were intended to used" ... that's a wrap.
Re: MFC - Cdialog::OnOK() in Thread
It doesn't matter if it looks lightweight - what matters is that the OnButtonTtlsRevs( ) method is called in the context of the secondary thread which is not allowed because you are calling MFC objects from there.
The simplest way to solve this is to follow Ovidiu's advice and post a user defined message.
First declare the user defined message (in stdafx.h)
Code:
#define WM_USER_TTLS_REVS WM_USER + 1
Next declare a message handler in the view class and call your existing OnButtonTotlsRevs() method.
Code:
afx_msg LRESULT OnTtlsRevs( WPARAM wParam, LPARAM lParam );
LRESULT CFormHdrView::OnTtlsRevs( WPARAM wParam, LPARAM lParam )
{
OnButtonTotlsRevs( );
}
Be sure to add the appropriate Message map entry for the user defined message
Code:
BEGIN_MESSAGE_MAP(CFormHdrView, CFormView)
ON_MESSAGE( WM_USER_TTLS_REVS, OnTtlsRevs )
END_MESSAGE_MAP()
Then modify the thread code to pass in the hWnd of the view class (use the GetSafeHWnd( ) method)....and post a message to the view inside the thread.
Code:
UINT WorkerThreadProc( LPVOID lParam )
{
HWND hWnd = (HWND)lParam;
ASSERT( NULL != hWnd );
// Pause a bit before sending the message
Sleep( 10000 );
// Send a message to the form view and cause it to click
// on the button
::PostMessage( hWnd, WM_USER_TTLS_REVS, 0, 0 );
// Pause here for a bit so the thread doesn't close
Sleep( 10000 );
return TRUE;
}
P.S. I through in a few sleep statements in the thread so things wouldn't happen to fast. Generally you wouldn't want these in a real app.
Re: MFC - Cdialog::OnOK() in Thread
I got that to work without the Assertion Messages, thanks.
Re: MFC - Cdialog::OnOK() in Thread
Quote:
Originally Posted by
ADSOFT
I got that to work without the Assertion Messages, thanks.
Your'e a genius. Sometimes even the wrong solution seem to work. Someday somebody will make a seemingly unimportant change to your form class and everything will blow up.
You seem not to understand that when a message handler in a class is invoked from another thread this can happen anywhere in the other threads context but if the other thread just posts a message to that thread it will be processed in a way that synchronisation is not even necessary.
Kurt
Re: MFC - Cdialog::OnOK() in Thread
Quote:
Originally Posted by
ZuK
Your'e a genius. Sometimes even the wrong solution seem to work. Someday somebody will make a seemingly unimportant change to your form class and everything will blow up.
You seem not to understand that when a message handler in a class is invoked from another thread this can happen anywhere in the other threads context but if the other thread just posts a message to that thread it will be processed in a way that synchronisation is not even necessary.
Kurt
Well, maybe you should learn how to read, or read all the posts before you put in your two centavos, or maybe you should spend some time on this continent so you can understand English a little bit better: I got Arjay's solution to work without the Assertion messages that I was getting by passing a CFormView pointer: Does that clarify things?
Now go back and read my previous post, and all the posts before that, ok!!
Btw, Thanks again to Arjay.:)
If I ever get my CFormView Class syncronized, I'm going to go to Austria, and take Arnold with me, just to make sure it works over there and they know how to use it. .... then I will get Arnold S. (You know the Terminator) to Email Mr. Kurt a.k.a Zuk, so he understands every little detail.
Hasta la Vista Baby :wave:
Re: MFC - Cdialog::OnOK() in Thread
Quote:
Originally Posted by
ADSOFT
Code:
UINT WorkerThreadProc( LPVOID Param ){
CFormHdrView *pCFV ;
pCFV = (CFormHdrView *)Param;
if(::gpCFVw_Hdr == NULL)::AfxMessageBox("Null Pointer");
...
}
Again it is wrong. :eek:
Don't pop up any window from within a worker thread! The illusion it sometimes "works" does not mean it is correct and will work for ever. Unfortunately no, it won't!
Re: MFC - Cdialog::OnOK() in Thread
Quote:
Originally Posted by
VictorN
Again it is wrong. :eek:
Don't pop up any window from within a worker thread! The illusion it sometimes "works" does not mean it is correct and will work for ever. Unfortunately no, it won't!
Well the problem is that you don't know how to explain yourself. If you would have pinpointed documentation stating that MFC obects should not be called from within threads, then I would have believed you. .... fortunately I found documention that states that.
Code:
CObject* p;
ASSERT((p = pMap->LookupPermanent(m_hWnd)) != NULL ||
(p = pMap->LookupTemporary(m_hWnd)) != NULL);
ASSERT((CWnd*)p == this); // must be us
// Note: if either of the above asserts fire and you are
// writing a multithreaded application, it is likely that
// you have passed a C++ object from one thread to another
// and have used that object in a way that was not intended.
// (only simple inline wrapper functions should be used)
//
// In general, CWnd objects should be passed by HWND from
// one thread to another. The receiving thread can wrap
// the HWND with a CWnd object by using CWnd::FromHandle.
//
// It is dangerous to pass C++ objects from one thread to
// another, unless the objects are designed to be used in
// such a manner.
Note where it says, ".... must be us". It's not my fault that Microsoft's objects can't run from threads.
I theory you should be able access any window from a global pointer, .... that's what Microsoft admits, when it says "..... it mus be us".
Instead of saying what should be done and not be done, why don't you quote the manufacture, i.e, Microsoft on the do's and don't of threads and MFC. You sound like your making the stuff up. Next time quote Microsoft on the limitation of Microsofts' products, not 3rd and 4rth party websites.:thumbd:
Re: MFC - Cdialog::OnOK() in Thread
Quote:
Originally Posted by
VictorN
Again it is wrong. :eek:
Don't pop up any window from within a worker thread! The illusion it sometimes "works" does not mean it is correct and will work for ever. Unfortunately no, it won't!
Look this is what you should have done from the very begining:
http://support.microsoft.com/kb/147578
Re: MFC - Cdialog::OnOK() in Thread
Quote:
Originally Posted by
ADSOFT
I have learned this hard way. Calling any MFC stuff that involves any GUI will surely fail sooner or later. I have spent weeks debugging and didn't understand why my application is throwing asserts.
The right approach is using GUI threads: sending message from dialog to thread and back as someone pointed that in this thread. Just derive your thread from CWinThread.
Sending data to thread is available via PostThreadMessage function.
Re: MFC - Cdialog::OnOK() in Thread
Quote:
Originally Posted by
streamer
I have learned this hard way. Calling any MFC stuff that involves any GUI will surely fail sooner or later. I have spent weeks debugging and didn't understand why my application is throwing asserts.
The right approach is using GUI threads: sending message from dialog to thread and back as someone pointed that in this thread. Just derive your thread from CWinThread.
Sending data to thread is available via PostThreadMessage function.
This is a common approach, however, I prefer to not use messaging to transfer data between threads. I simply put any data that needs to be shared between threads in a class, expose the data via thread safe accessor methods, and then pass a pointer of the class to the threads. I use user defined messages, but these are only used by worker threads to signal the UI thread that the data has changed (whereby the UI thread gets the data from the thread safe accessor methods). I find that this approach is cleaner and requires fewer message handlers.