Sharing App CMDIFrameWnd with user-interface threads
Posted on 1997-02-22
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);
ASSERT(pMap->LookupPermanent(m_hWnd, p) ||
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.
***** 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.
// 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
in CMDIChildWnd::GetMDIFrame() member function
ASSERT(m_hWnd != NULL);
HWND hWndMDIClient = ::GetParent(m_hWnd);
ASSERT(hWndMDIClient != NULL);
pMDIFrame = (CMDIFrameWnd*)CWnd::FromHandle(::GetParent(hWndMDIClient));
ASSERT(pMDIFrame != NULL);
**** ASSERT FIRES ASSERT_KINDOF(CMDIFrameWnd, pMDIFrame);
ASSERT(pMDIFrame->m_hWndMDIClient == hWndMDIClient);
What am I doing wrong???