July 30, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

How to Avoid an MFC Active Document Container from Hanging

  • September 20, 2000
  • By Carsten Breum
  • Send Email »
  • More Articles »

Steps to Reproduce

In order to fully understand the problem, perform one of the following two steps ("Creating an Active Document Container" or "Creating an Active Document Server That Contains a Rich Edit Control") as follows.

Creating an Active Document Container

  1. Using Visual Studio, create an MFC project (any name will do for the purposes of this demo).
  2. Click the Active document container checkbox.

  3. Click the Finish button

Creating an Active Document Server That Contains a Rich Edit Control

  1. Using Visual Studio, create an MFC project (any name will do for the purposes of this demo).
  2. Click mini-server and check Active document server checkbox.
  3. Select a CFormView instead of the CView.
  4. Click the Finish button.
  5. In the resource editor, drag a rich edit control to the form.
  6. Insert a call to AfxInitRichEdit() in the application object's InitInstance function.
  7. Compile and run the server to get it registered in registry.

Understanding the Problem

Now that you've created a demo application, let's see the problem up close.
  1. Run the test container application
  2. Select to inplace active an object.
  3. From the dialog, select the server you just created.
  4. Close the application
  5. The program hangs every time!

How the Problem Can Be Solved

Ok. Now we see there's a problem. How can it be solved?

In the OnCloseDocument method in the container the COleClientItem(COleDocObjectItem) object is released with a call to InternalRelease(). But since the member variable m_dwRef is 8 InternalRelease does not call OnFinalRelease and therefore the server is never totally released. For a server that does not contain a rich edit control m_dwRef is 1. Well, what can we do about that? The obvious thing is to call release on the COleClientItem until it is one, but that causes an exception in Ole32.dll, so that's not the solution.

I found a way to deal with the problem by adding some code to the OnClose method in the CMainFrame class. MFC uses an AFX_MODULE_STATE object to manage the MDI windows used in the container. During a normal CMDIFrameWnd::OnClose() call a call to CloseAllDocuments(...) is made, but if the m_nObjectCount in the AFX_MODULE_STATE is not 0 then the application is not closed down. What I did was to call CloseAllDocuments() before calling OnClose(), but before the call to OnClose is made the m_nObjectCount value is checked. If it's not 0 then AfxOleUnlockApp() is called. In the OnClose() ObjectCount is now 0 and the call to AfxOleCanExitApp() in OnClose returns true which causes the application to shutdown!

Code to Fix the Problem

Here's the code I used to finally fix this problem.

void CMainFrame::OnClose()
{
 AFX_MODULE_STATE* pModuleState = AfxGetModuleState();
 TRACE("module count %d\n", pModuleState->m_nObjectCount);

 try
 { 
  int incOleLock=0;

  // m_nObjectCount is telling how many mdi windows 
  // that are open (I guess)

  // This is called to make the objectCount go as low as possible.
  AfxGetApp()->CloseAllDocuments(FALSE);  
  while(pModuleState->m_nObjectCount > 0) 
  { 
   // If we end up here then and object "hangs"

   // This is called BEFORE OnClose to make the OnClose destroy the window
   AfxOleUnlockApp();

   // This tells us to remember to increment the object count
   // AFTER the window is destroyed
   incOleLock++; 
  }
  CMDIFrameWnd::OnClose();
  while(incOleLock)
  {
   // incerement ObjectCount to let the hanging object close
   // down itself.
   AfxOleLockApp(); 

   incOleLock--;
  }
 }
 catch(...)
 {
  TRACE("Exception thrown during void CMainFrame::OnClose() shutdown\n");
  }
}

Downloads

Download source - 79 Kb






Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Sitemap | Contact Us

Rocket Fuel