Sharing App CMDIFrameWnd with user-interface threads

Posted on 1997-02-22
Last Modified: 2008-02-20
Visual C++ V.4.0  and MFC

Is it possible to share the Application's CMDIFrameWnd object with
another User interface thread?  If so, how.  Making member functions thread safe is easy, but how can
I make CMDIFrameWnd data members thread safe?  

i.e. I'm trying to share    theApp.m_pMainWnd <-- CMDIFrameWnd
     in an MDI application.

Scenario:      MDI(Multiple Document Interface) application.

Need to create/open a CMDIChildWnd object in a thread because it's time consuming.  The entire process of creating and opening CMDIChildWnd is slow, not just a component, so a worker thread is not really an option.

If specify, theApp.m_pMainWnd as a new CWinThread member(m_pMainWnd), creation of child window fails on assert(wincore.cpp line 872)     AssertValid function.

void CWnd::AssertValid() const
      // check for special wnd??? values
      ASSERT(HWND_TOP == NULL);       // same as desktop
      if (m_hWnd == HWND_BOTTOM)
            ASSERT(this == &CWnd::wndBottom);
      else if (m_hWnd == HWND_TOPMOST)
            ASSERT(this == &CWnd::wndTopMost);
      else if (m_hWnd == HWND_NOTOPMOST)
            ASSERT(this == &CWnd::wndNoTopMost);
            // should be a normal window

            // should also be in the permanent or temporary handle map
            CHandleMap* pMap = afxMapHWND();
            ASSERT(pMap != NULL);

            CObject* p;
            ASSERT(pMap->LookupPermanent(m_hWnd, p) ||
                  pMap->LookupTemporary(m_hWnd, p));
            ASSERT((CWnd*)p == this);   // must be us                            
line 872

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

***** tried this too, didn't work
// It is dangerous to pass C++ objects from one thread to
// another, unless the objects are designed to be used in
// such a manner.

yeah, yeah I know, this is
exactly what I'm trying to do
is it possible or do I need another  approch

So, far all the results of this make sense.  Trying to access a windows object created in another thread
is a no-no, so I tried the next approach.

Create a User interface using CRunTimeClass information.   Assign new thread a new CMDIFrameWnd
object to  CWinThread's  m_pMainWnd member.

BOOL UserInterfaceThread::InitInstance()
   // create main MDI Frame window

   CMDIFrameWnd *Frame = new CMDIFrameWnd;
   if (! Frame->LoadFrame(IDR_MAINFRAME)) return(FALSE);
   m_pMainWnd = Frame;

   // The main window has been initialized, so show and update it.

 CMDIChildWnd *pChild = new CMDIChildWnd(....);     // works great

   pChild->ShowWindow(SW_SHOW);      // works great

 // at this point I can see Child window, use all of its menus, features etc.
// the child window is running normally in its own thread

 pChild->DestroyWindow();       // ka-boom chokes on
         ASSERT_KINDOF(CMDIFrameWnd, pMDIFrame);

in   CMDIChildWnd::GetMDIFrame()    member function


CMDIFrameWnd* CMDIChildWnd::GetMDIFrame()
      ASSERT_KINDOF(CMDIChildWnd, this);
      ASSERT(m_hWnd != NULL);
      HWND hWndMDIClient = ::GetParent(m_hWnd);
      ASSERT(hWndMDIClient != NULL);

      CMDIFrameWnd* pMDIFrame;
      pMDIFrame = (CMDIFrameWnd*)CWnd::FromHandle(::GetParent(hWndMDIClient));
      ASSERT(pMDIFrame != NULL);
      ASSERT(pMDIFrame->m_hWndMDIClient == hWndMDIClient);
      return pMDIFrame;
What am I doing wrong???

Question by:langer
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
1 Comment
LVL 11

Accepted Solution

mikeblas earned 100 total points
ID: 1161981

This question deals squarely with MFC.  Why isn't it in
the MFC Section?

Anyway, you asked: "I make CMDIFrameWnd data members thread safe?"

The easiest way would be to wrap them in accessor functions.  You
should put a CCriticalSection member in your class, and then
call Lock() on the critical section and then Unlock() on the way
out.  Let's assume you call this new member m_critSec.

So, instead of just using member variables like "pObject->m_nCount"
directly, you should add a GetCount() and SetCount() function:

void CYourClass::SetCount(int nCount)
   m_nCount = nCount;

int CYourClass::GetCount()
   int nRetVal;
   nRetVal = m_nCount;
   return nRetVal;

You also said:

 > I'm trying to share theApp.m_pMainWnd <-- CMDIFrameWnd
 > in an MDI application.

You can't pass a CWnd* pointer owned by one thread to another
thread.  theApp.m_pMainWnd's use as a window wrapper will only
be available in the main thread of your application, then.

So, in subordinate threads, you should get started by doing
something like:

   CWnd* pWnd = CWnd::FromHandle(theApp.m_pMainWnd->m_hWnd);

and using that pWnd in your subordinate thread.  There are lots
of rules which dictate the exact use and function of this kind
of thing; most notably, there will still be times that you can
(and must) use theApp.m_pMainWnd from your subordinate thread.

There are lots of books (and many places in the online documentation) where those rules are described.

.B ekiM


Featured Post

Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

This article will show you some of the more useful Standard Template Library (STL) algorithms through the use of working examples.  You will learn about how these algorithms fit into the STL architecture, how they work with STL containers, and why t…
Go is an acronym of golang, is a programming language developed Google in 2007. Go is a new language that is mostly in the C family, with significant input from Pascal/Modula/Oberon family. Hence Go arisen as low-level language with fast compilation…
The viewer will learn how to use the return statement in functions in C++. The video will also teach the user how to pass data to a function and have the function return data back for further processing.
The viewer will learn how to clear a vector as well as how to detect empty vectors in C++.

728 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