You should not be calling AfxGetMainWnd in a worker thread

Author Problems Initializing in the MainFrame
http://www.codecomments.com/archive372-2006-4-890607.html
Joe

2006-04-14, 7:09 pm

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" <Joe@discussions.microsoft.com> 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" <Joe@discussions.microsoft.com> 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;
> .
>
> // 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++]
ajaykalra@yahoo.com


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
Joe

2006-04-14, 7:09 pm

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?
Joe

2006-04-14, 7:09 pm

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().
Joe

2006-04-14, 7:09 pm

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

Joe

2006-04-14, 7:09 pm

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" <Joe@discussions.microsoft.com> wrote in message
news:313D23C0-E3AD-42FB-A926-A50A91BB979E@microsoft.com...
> 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?
>
>



Joe

2006-04-14, 7:09 pm

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?
Joe

2006-04-14, 7:09 pm

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.
Joe

2006-04-14, 7:09 pm

>
> 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).

posted on 2006-11-04 22:37  cy163  阅读(1402)  评论(0编辑  收藏  举报

导航