BUG: GDI Leaks Memory When Font Selected In MM_ISOTROPIC and MM_ANISOTROPIC Mode (149289)



The information in this article applies to:

  • Microsoft Platform Software Development Kit (SDK) 1.0
  • Microsoft Win32 Application Programming Interface (API)
  • Microsoft Windows 95
  • Microsoft Windows 95 OEM Service Release 95
  • Microsoft Windows 98
  • Microsoft Windows 98 Second Edition

This article was previously published under Q149289

SYMPTOMS

Selecting a previously selected HFONT (handle to a font object) back into a device context may result in a 52-byte memory leak if and only if the mapping mode is set to MM_ISOTROPIC or MM_ANISOTROPIC, and the window or viewport extents have changed.

The operating system can eventually stop responding ("hang"), due to lack of resources.

This problem can occur only when all of the following conditions are met:
  • The device context mapping mode is set to MM_ISOTROPIC or MM_ANISOTROPIC (via a call to SetMapMode()).
  • A new font of any type is selected into the device context (via a call to SelectObject()). It is assumed that the font handle returned by SelectObject() is stored by the application for later reselection into the current device context.
  • The window extents or viewport extents are changed (via a call to SetWindowExtEx() or SetViewportExtEx()).
  • A previous font is selected back into the device context. This is where the memory leak occurs.
Even though this situation is most likely to arise during WM_PAINT message handling, the coded conditions may not all be local to a WM_PAINT message handler, especially if either the CS_CLASSDC or the CS_OWNDC style bit is set when the window class is registered.

This is because the device context and its attributes are retained across calls to GetDC(), BeginPaint, and GetDCEx(). Use of the DCX_CACHE bit with GetDCEx() complicates matters somewhat, but the specific conditions for the memory leak to manifest hold true for the lifetime of the device context in question. Memory and printer device contexts can also be affected by this problem.

CAUSE

When a font is selected into a device context, the current window and viewport extents are copied to a structure that is stored in an internal font instance heap. This structure also tracks font transform data used by the font mapper when finding the closest match for a logical font.

When another font is selected into the device context, the current font instance is detached from the device context. If the original font is again selected into the device context, a search is conducted in this heap for the original font instance data, so that it can be reused.

The lookup criteria to find the font includes the window and viewport extents. If either of these extents have changed since the current font was selected (and the mapping mode is MM_ISOTROPIC or MM_ANISOTROPIC), then the lookup fails and the font transform data item is orphaned, which results in a loss of 52 bytes of memory.

Note that the values for the window and viewport origins do not affect this problem.

RESOLUTION

In order to minimize or eliminate this problem, the following methodology is recommended:

Window Class CS_CLASSDC and CS_OWNDC Style Bits Not Set

  1. Select a new font.
  2. Set a new map mode.
  3. Set the new extents (save current extents).
  4. Draw or output text.
  5. Restore the original extents.
  6. Restore the original mapping mode.
  7. Select the original font.
Sample Code:
   SIZE sWinExt = {2,2};
   SIZE sOldWinExt = {1,1};

   LRESULT APIENTRY WndProc(HWND hwnd, UINT message, WPARAM wParam,
                            LPARAM lParam)
   {
      HDC hDC;
      HFONT hFont;
      PAINTSTRUCT ps;
      int  nOldMapMode;

      switch (message) {
      case WM_PAINT:
         hDC = BeginPaint(hwnd,&ps);
         nOldMapMode = GetMapMode(hDC);
         SetMapMode(hDC,MM_ISOTROPIC);
         hFont = SelectObject(hDC,GetStockObject(ANSI_VAR_FONT));
         SetWindowExtEx(hDC,sWinExt.cx,sWinExt.cy,&sOldWinExt);
         // Draw, output text, and so on.
         SetWindowExtEx(hDC,sOldWinExt.cx,sOldWinExt.cy,NULL);
         SetMapMode(hDC,nOldMapMode);
         SelectObject(hDC,hFont);
         EndPaint(hwnd, &ps);
         return 0;
      .
      .
      .
				

Window Class CS_CLASSDC or CS_OWNDC Style Bit Set

This type of device context lifetime is often implemented in applications as a means of quickly redrawing scaled views without completely setting up the device context every time it is retrieved.

NOTE: These steps assume that either the MM_ISOTROPIC or MM_ANISOTROPIC mapping mode is set (in the WM_CREATE message handler, for example).
  1. Select a new font.
  2. Set new extents (save current extents).
  3. Draw or output text.
  4. Restore the original extents.
  5. Select the original font.
Sample Code:
   SIZE sWinExt = {2,2};
   SIZE sOldWinExt = {1,1};

   LRESULT APIENTRY WndProc(HWND hwnd, UINT message, WPARAM wParam,
                            LPARAM lParam)
   {
      HDC hDC;
      HFONT hFont;
      PAINTSTRUCT ps;

      switch (message) {
      case WM_PAINT:
         hDC = BeginPaint(hwnd,&ps);
         hFont = SelectObject(hDC,GetStockObject(ANSI_VAR_FONT));
         SetWindowExtEx(hDC,sWinExt.cx,sWinExt.cy,&sOldWinExt);
         // Draw, output text, and so on.
         SetWindowExtEx(hDC,sOldWinExt.cx,sOldWinExt.cy,NULL);
         SelectObject(hDC,hFont);
         EndPaint(hwnd, &ps);
         return 0;
      .
      .
      .
				
WARNING: ANY USE BY YOU OF THE CODE PROVIDED IN THIS ARTICLE IS AT YOUR OWN RISK. Microsoft provides this code "as is" without warranty of any kind, either express or implied, including but not limited to the implied warranties of merchantability and/or fitness for a particular purpose.

STATUS

Microsoft has confirmed that this is a problem in the Microsoft products that are listed at the beginning of this article.

This problem was corrected in Windows Millennium Edition.

NOTE: The changes in Windows Millennium Edition resolve the problem for stock fonts only.

MORE INFORMATION

A certain amount of font object instance data is retained in a device context during normal application WM_PAINT message handling, as well as in the specific scenarios noted at the end of this section.

The font instance heap can be expected to take an initial "hit" of two new entries, as the new and "original" font objects are realized, which occurs when they are selected into the device context, and rendering occurs.

Font object instance data attached to a device context is typically reused and deallocated when the device context is destroyed, which generally occurs under the following conditions:
  • The last existing window for a CS_CLASSDC class is destroyed.
  • The current window for a CS_OWNDC window class is destroyed.
  • A device context obtained from GetDCEx() with the DCX_CACHE flag bit set is deleted by a call to DeleteDC().

Modification Type:MinorLast Reviewed:6/5/2006
Keywords:kbHotfixServer kbQFE kbDSWGDI2003Swept kbbug kbnofix KB149289