Sharing App CMDIFrameWnd with user-interface threads

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);
      else
      {
            // should be a normal window
            ASSERT(::IsWindow(m_hWnd));

            // 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.
   Frame->ShowWindow(SW_SHOW);
   Frame->UpdateWindow();

 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

hence..

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 FIRES      ASSERT_KINDOF(CMDIFrameWnd, pMDIFrame);
      ASSERT(pMDIFrame->m_hWndMDIClient == hWndMDIClient);
      ASSERT_VALID(pMDIFrame);
      return pMDIFrame;
}
 
What am I doing wrong???

langerAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

mikeblasCommented:

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_critSec.Lock();
   m_nCount = nCount;
   m_critSec.Unlock();
}

int CYourClass::GetCount()
{
   int nRetVal;
   m_critSec.Lock();
   nRetVal = m_nCount;
   m_critSec.Unlock();
   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




0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
C++

From novice to tech pro — start learning today.