Title: CPP9305: Temporary Object Memory Leak in Foundation Classes 
Document Number: Q98867           Publ Date: 30-JUN-1993 
Product Name: Microsoft C++ Foundation Classes 
Product Version:  2.00 
Operating System: MS-DOS 

 ---------------------------------------------------------------------- 
 The information in this article applies to: 
  - Microsoft Foundation Classes for Windows, version 2.0 
 ---------------------------------------------------------------------- 
 Summary: 
 PROBLEM ID: CPP9305001 
 SYMPTOMS 
    Under some circumstances, an application created with Microsoft 
    Foundation Classes version 2.0 allocates temporary objects on the 
    application heap and does not delete them. While the memory 
    diagnostics in the debugging version of the Foundation Classes 
    libraries do not detect this memory leak, the error is apparent 
    when Heap Walker is used to monitor the heap. 
 CAUSE 
    A HANDLE is attached to both a permanent object and a temporary 
    object. When the HANDLE is detached from the permanent object, it 
    is also detached from the temporary object. Consequently, the 
    temporary object is never destroyed. 
 RESOLUTION 
    Do not remove the HANDLE from the temporary map when it is 
    detached. To do so, remove one line of code from the WINHAND.CPP 
    source file. In Visual C++, remove line 158 which reads as follows: 
       m_temporaryMap.RemoveKey((MAPTYPE)h); 
    It is also necessary to change the arguments to some ASSERT macros 
    to prevent detaching a temporary object from causing an assertion 
    failure. It is not necessary to Detach a temporary object because 
    it generally serves no useful purpose. However, because Microsoft 
    Foundation Class Libraries version 1.0 support this practice, 
    version 2.0 supports it as well. In WINHAND.CPP, change lines 145 
    and 173 from 
       ASSERT(ph[0] == h); 
    to: 
       ASSERT(ph[0] == h || ph[0] == NULL); 
    After making these changes, rebuild the Microsoft Foundation Class 
    Libraries using the MAKEFILE in the library source directory (by 
    default, C:\MSVC\MFC\SRC). The MAKEFILE supports building all 
    variations of the Foundation Class Libraries. For more information 
    on using the MAKEFILE, please refer to the comments at the 
    beginning of the MAKEFILE. 
 STATUS 
    Microsoft has confirmed this to be a problem in the Microsoft 
    Foundation Class Libraries version 2.0 for Windows. We are 
    researching this problem and will post more information here as it 
    becomes available. 
 More Information: 
 The Foundation Class Libraries maintain two maps for each HANDLE used 
 in the Microsoft Windows environment. The Libraries maintain four map 
 pairs, for HDCs, HGDIOBJECTs, HMENUs, and HWNDs. For each handle type, 
 the Libraries maintain two separate maps: a temporary map and a 
 permanent map. When the Library maps a HANDLE to a C++ object, it 
 checks the permanent map first and then checks the temporary map. 
 Under some circumstances, a HANDLE appears in both maps. A serious 
 memory leak occurs when a HANDLE is Detached (or unmapped) from its 
 permanent C++ object. This removes the HANDLE from both maps even 
 though the temporary object is not destroyed. Because the temporary 
 C++ object is not present in the temporary map when the 
 CWinApp::OnIdle() function attempts to delete all temporary objects, 
 the temporary C++ object remains in memory. For example, the following 
 code example causes a memory leak that involves one temporary CDC 
 object: 
    CDC* pDC = CDC::FromHandle(hDC); // creates temporary object 
    CDC dc; 
    dc.Attach(hDC); // now in permanent map as well 
    dc.Detach(hDC); // removed from temp and permanent map 
    // pDC is never deleted 
 Even though the code sequence above is rare, it occurs quite often 
 processing objects in the CFrameWnd class. CFrameWnd processes a 
 WM_ERASEBKGND message in an OnEraseBkgnd handler. Windows sends 
 WM_ERASEBKGND before it sends the WM_PAINT message. The Library 
 creates a temporary object in the OnEraseBkgnd handler. When the 
 application receives the WM_PAINT message, it creates a permanent 
 CPaintDC object on the stack. This creates a situation similar to that 
 above except that the temporary and permanent objects result from 
 processing different messages. 
 Because CWinApp::OnIdle() is not called between the WM_ERASEBKGND 
 message and WM_PAINT messages, the temporary object created processing 
 the WM_ERASEBKGND message is not removed. 
 This problem does not generally affect applications created in 
 AppWizard because CFrameWnd objects in an application that uses CView 
 child windows do not receive WM_PAINT messages under normal 
 circumstances. 
 Additional reference words: 2.00 

COPYRIGHT Microsoft Corporation, 1993.
