Author |
Problems Initializing in the MainFrame |
http://www.codecomments.com/archive372-2006-4-890607.html |
|
Hi. I’ve seen a very similar message already posed on this topic, but I didn’t see a solution that pertains to my case. I want to add some code to my MainFrame, and figured that I should do all initialization in the OnCreate(). Is this correct? Anyway, The OnCreate that was generated by the Wizard (CFormView SDI app) is:
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct} {
if (CFrameWnd::OnCreate(lpCreateStruct) == -1) return -1; …
// My test code CWnd* t = AfxGetMainWnd();
}
If I try to get the frame address with AfxGetMainWnd() as depicted above I get a NULL.
Is there a better place to put one time initialization code where AfxGetMainWnd() will actually have the pointer to my MainFrame? I know it’s correct by the time it hits the OnInitialUpdate() in my View – I’m trying to figure the best place to put the same code in my MainFrame. Obviously, the “this†pointer is correct inside OnCreate(), but in this part of my initialization code I need the AfxGetMainWnd() function to return the pointer to the MainFrame.
Thanks.
|
|
Tom Serface 2006-04-14, 7:09 pm |
|
The pointer is assigned when the window is created in InitInstance() (main code). You could walk through that function and see when the window is created.
Tom
"Joe" <[email protected]> wrote in message news:5B834110-CA60-4C52-938F-124302BA497A@microsoft.com... > Hi. I've seen a very similar message already posed on this topic, but I > didn't see a solution that pertains to my case. I want to add some code to > my > MainFrame, and figured that I should do all initialization in the > OnCreate(). > Is this correct? Anyway, The OnCreate that was generated by the Wizard > (CFormView SDI app) is: > > int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct} { > > if (CFrameWnd::OnCreate(lpCreateStruct) == -1) > return -1;
|
|
Ajay Kalra 2006-04-14, 7:09 pm |
|
"Joe" <[email protected]> wrote in message news:[email protected]... > Hi. I've seen a very similar message already posed on this topic, but I > didn't see a solution that pertains to my case. I want to add some code to my > MainFrame, and figured that I should do all initialization in the OnCreate(). > Is this correct? Anyway, The OnCreate that was generated by the Wizard > (CFormView SDI app) is: > > int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct} { > > if (CFrameWnd::OnCreate(lpCreateStruct) == -1) > return -1; > . > > // My test code > CWnd* t = AfxGetMainWnd(); > > } > > If I try to get the frame address with AfxGetMainWnd() as depicted above I > get a NULL. >
You are using AfxGetMainWnd, which uses a member variable which gets set later on in CWinApp. In your case, you can use "this" rather than AfxGetMainWnd.
-- Ajay Kalra [MVP - VC++] [email protected]
|
|
David Wilkinson 2006-04-14, 7:09 pm |
|
Joe wrote:
> Hi. I’ve seen a very similar message already posed on this topic, but I > didn’t see a solution that pertains to my case. I want to add some code to my > MainFrame, and figured that I should do all initialization in the OnCreate(). > Is this correct? Anyway, The OnCreate that was generated by the Wizard > (CFormView SDI app) is: > > int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct} { > > if (CFrameWnd::OnCreate(lpCreateStruct) == -1) > return -1; > … > > // My test code > CWnd* t = AfxGetMainWnd(); > > } > > If I try to get the frame address with AfxGetMainWnd() as depicted above I > get a NULL. > > Is there a better place to put one time initialization code where > AfxGetMainWnd() will actually have the pointer to my MainFrame? I know it’s > correct by the time it hits the OnInitialUpdate() in my View – I’m trying to > figure the best place to put the same code in my MainFrame. Obviously, the > “this†pointer is correct inside OnCreate(), but in this part of my > initialization code I need the AfxGetMainWnd() function to return the pointer > to the MainFrame. > > Thanks.
Joe:
AfxGetMainWnd() returns the m_pMainWnd member of your application object, but in SDI this member is not set until after the main frame, document and view are created. This can be a problem in the document and the view. But in the MainFrame itself, you already have the "this" pointer, so why do you need AfxGetMainWnd()?
Maybe I'm missing something here.
David Wilkinson
|
|
|
Tom - thanks for the reply. I was hoping to put this code in my MainFrame not in my App. Do you know of somewhere in my MainFrame I could put it?
|
|
|
Ajay - thanks for your reply. The problem isn’t that I don’t know the MainFrame pointer in my MainFrame (obviously I do), the problem is that I’m trying to start a thread in my MainFrame. The thread starts OK, but when it starts it gets the owner window, which when I start the thread in the MainFrame the owner window is NULL, so when I call AfxGetMainWnd() inside the thread I always get a NULL pointer (even though the Frame is already created and the window is visible). I know I can create a function to return a pointer to the MainFrame, but I didn’t have any problem with similar threads that I started from my View – because the pointer was valid when I created the thread in MyView::OnInitalUpdate().
|
|
|
David - thanks for your reply. It looks like you and Ajay were thinking the same thing at the same time. You can look up at my response to him, but basically I need AfxGetMainWnd() to work in a thread I'm starting inside the MainFrame - and it always returns NULL because I'm starting it in the MainFrame.
|
|
Ajay Kalra 2006-04-14, 7:09 pm |
|
You should not be calling AfxGetMainWnd in a worker thread. These windows pointers are stored in TLS and generally you should not use them outside the thread these were created. You can pass the window handle to the thread.
In your case this is what I would do:
In CYouApp::InitInstance, post a custom message to mainframe after it has been created. In the handler of this message, start your thread. OR
Start your thread in InitInstance after the mainframe is created.
--- Ajay
|
|
|
Ajay – yeah, I think either way you suggest would work OK, thanks.
> You should not be calling AfxGetMainWnd in a worker thread. These > windows pointers are stored in TLS and generally you should not use > them outside the thread these were created.
I’m wondering about your comment. The documentation for AfxGetMainWnd() says: if the function is called from a secondary thread in the application (which is what I’m doing), the function returns the main window associated with the thread that made the call. This is why AfxGetMainWnd() works properly with I start the thread from CMyView::OnInitalUpdate() and not from CMainFrame::OnCreate(). Are you thinking that it may not be safe to call it in any of my Worker threads?
|
|
Scott McPhillips [MVP] 2006-04-14, 7:09 pm |
|
Joe wrote: > I’m wondering about your comment. The documentation for AfxGetMainWnd() > says: if the function is called from a secondary thread in the application > (which is what I’m doing), the function returns the main window associated > with the thread that made the call. This is why AfxGetMainWnd() works > properly with I start the thread from CMyView::OnInitalUpdate() and not from > CMainFrame::OnCreate(). Are you thinking that it may not be safe to call it > in any of my Worker threads?
Worker threads do not have a main window "associated with the thread." AfxGetMainWnd() should return NULL from such threads.
-- Scott McPhillips [VC++ MVP]
|
|
David Wilkinson 2006-04-14, 7:09 pm |
|
Joe wrote:
> David - thanks for your reply. It looks like you and Ajay were thinking the > same thing at the same time. You can look up at my response to him, but > basically I need AfxGetMainWnd() to work in a thread I'm starting inside the > MainFrame - and it always returns NULL because I'm starting it in the > MainFrame.
Joe:
If this is a worker thread, pass the "this" pointer as LPVOID parameter.
I forget if it is OK to call AfxGetMainWnd() from a thread (Ajay says not), but if it is, one simple way to get AfxGetMainWnd() to return the correct value sooner is to do
AfxGetApp()->m_pMainWnd = this;
in your MainFrame constructor. Bad OOP, but effective.
David Wilkinson
|
|
Tom Serface 2006-04-14, 7:09 pm |
|
I didn't catch that you were calling this from a worker thread. You need to be careful about that one since worker threads are not supposed to access GUI windows. You can send a message to the mainframe to tell it to do something for you, but you'll have to set the CWnd * pointer by calling a function in the thread object... I usually use something like: SetMessageWnd(CWnd *pWnd); Then you can do a pWnd->PostMessage(...) to tell the GUI thread you want it to do something. However, don't update any of the windows directly and, I've found, you should use PostMessage rather than SendMessage.
Tom
"Joe" <[email protected]> wrote in message news:[email protected]... > Ajay - yeah, I think either way you suggest would work OK, thanks. > > > > I'm wondering about your comment. The documentation for AfxGetMainWnd() > says: if the function is called from a secondary thread in the application > (which is what I'm doing), the function returns the main window associated > with the thread that made the call. This is why AfxGetMainWnd() works > properly with I start the thread from CMyView::OnInitalUpdate() and not > from > CMainFrame::OnCreate(). Are you thinking that it may not be safe to call > it > in any of my Worker threads? > >
|
|
|
Scott - thanks for your reply. I guess it depends on where you start the thread. When I start the thread from my View, AfxGetMainWnd() always works. When I start it from my MainFrame, AfxGetMainWnd() always return NULL. Maybe the difference is that the pointer has been initialized in my View, but not in the MainFrame yet?
|
|
|
Tom, right! I have several threads in my View and when they need to communicate with the View they use a function that I created: CMyView* GetView() that returns a pointer to the View. When I use GetView() and AfxGetMainWnd() I only use it with PostMessage() and make custom messages for communication. Yeah, SendMessage() doesn't do the trick all of the time - it can temporarily hang my worker thread and add additional coupling that I don't want.
|
|
> > AfxGetApp()->m_pMainWnd = this; >
That's exactly it, thanks! When I put that just before where I spawn my thread inside of CMainFrame::OnCreate(...) then AfxGetMainWnd() now returns the correct pointer (in OnCreate() and in my thread). Your code just allows me to initialize the pointer to what it should be a little sooner than it would occur naturally. I was playing around with m_pMainWnd yesterday, but didn't get the correct syntax/function to get it to work properly (like you did). |
|