We help IT Professionals succeed at work.

We've partnered with Certified Experts, Carl Webster and Richard Faulkner, to bring you a podcast all about Citrix Workspace, moving to the cloud, and analytics & intelligence. Episode 2 coming soon!Listen Now

x

GDI memory leaks when using Palettes in Metafiles

dregan
dregan asked
on
Medium Priority
776 Views
Last Modified: 2013-12-03
BoundsChecker throws up a memory leak error in GDI when using the following code

HDC      m_hrefdc, m_hmfdc;
HPALETTE hpal, psel;
RECT m_refrect;

m_hrefdc = CreateDC("DISPLAY", NULL, NULL, NULL);
m_hmfdc  = CreateEnhMetaFile(m_hrefdc, NULL, &m_refrect, "Test Metafile");
hpal     = CreatePalette( plogp );/** BOUNDSCHECKER ERROR **/
psel     = SelectPalette( m_hmfdc, hpal, FALSE );
DeleteObject( psel );

RealizePalette( m_hmfdc );
( perform GDI commands on metafile )

m_mfhndl = CloseEnhMetaFile(m_hmfdc);
( Use metafile )

DeleteEnhMetaFile(m_MetaFile)

The problem is that when the metafile is created, m_hmfdc is
invalidated, so the new palette cannot be selected out of it to be deleted.
Does anyone know of a workaround for this, or is it a
BoundsChecker artifact ?
Comment
Watch Question

Commented:
Why would m_hmfdc be invalidated?
Where is the palette?  If you selected it into m_hrefdc then, you should be able to select it out.  It should not be invalidated.  At least not that I know of.
ete

Commented:
There is a very obvious memory leak according to your code fragment. You create a GDI object hpal, but you do not delete it. When ever you use CreatePalette() API, make sure you use DeleteObject() for the returned handle when you no longer need the object.

Also, depending on the handling of this code, there might be another problem as well. If this is from WM_PAINT or WM_ERASEBKGND for instance, you should not call DeleteObject() for the returned handle of SelectObject(). Instead after SelectObject() you do your things, then call SelectObject() again with the previously returned value and then call DeleteObject() for the palette you created.

Regards,
ETE

Author

Commented:
The hpal cannot be deleted because it is selected into the metafile DC.

The metafile DC is closed by the call to the CloseEnhMetafile(..) function (see MSDN documentation) --- this is where we would expect the palette memory to be freed.

If we selected the palette object out of  the metafile DC, in order to delete it, then the palette information in the metafile header would be wrong.
ete

Commented:
Still not quite right. Whenever you use CreatePalette(), you must have a corresponding call to DeleteObject(), otherwise there is a memory leak. See CreatePalette() documentation. BoundsChecker correctly shows it to you. Your call to DeleteObject() is for wrong object and in wrong place.

CloseEnhMetaFile() does not delete the GDI object what you created, it just returns the handle for you to use. DeleteEnhMetaFile() releases the metafile handle, but again it does not delete the GDI object hpal that you created.

With the CreateDC() call you obtain the display device context, which you use as reference device context in your call to CreateEnhMetaFile()to create a metafile device context. The created/obtained reference dc should also be deleted with DeleteDC().

There seems to be a spelling mistake (I guess...) in the calls to CloseEnhMetaFile() and DeleteEnhMetaFile(). The returned handle from the previous call is what you should pass to the second call as a parameter.

More accurate code could look like:


HDC m_hrefdc, m_hmfdc = NULL;
HPALETTE hpal = NULL;
RECT m_refrect;
HENHMETAFILE m_mfhndl = NULL;

m_hrefdc = CreateDC("DISPLAY", NULL, NULL, NULL);
m_hmfdc = CreateEnhMetaFile(m_hrefdc, NULL, &m_refrect, "Test Metafile");

hpal = CreatePalette( plogp );
SelectPalette( m_hmfdc, hpal, FALSE );

RealizePalette( m_hmfdc );

( perform GDI commands on metafile )

m_mfhndl = CloseEnhMetaFile(m_hmfdc);

( Use metafile )

// release the metafile handle, same handle that was
// returned earlier
DeleteEnhMetaFile(m_mfhndl);

//destroy all created and not any more needed GDI objects
DeleteObject( hpal );
DeleteDC(m_hrefdc);
 
Regards,
Ete

Commented:
Still not quite right. Whenever you use CreatePalette(), you must have a corresponding call to DeleteObject(), otherwise there is a memory leak. See CreatePalette() documentation. BoundsChecker correctly shows it to you. Your call to DeleteObject() is for wrong object and in wrong place.

CloseEnhMetaFile() does not delete the GDI object what you created, it just returns the handle for you to use. DeleteEnhMetaFile() releases the metafile handle, but again it does not delete the GDI object hpal that you created.

With the CreateDC() call you obtain the display device context, which you use as reference device context in your call to CreateEnhMetaFile()to create a metafile device context. The created/obtained reference dc should also be deleted with DeleteDC().

There seems to be a spelling mistake (I guess...) in the calls to CloseEnhMetaFile() and DeleteEnhMetaFile(). The returned handle from the previous call is what you should pass to the second call as a parameter.

More accurate code could look like:


HDC m_hrefdc, m_hmfdc = NULL;
HPALETTE hpal = NULL;
RECT m_refrect;
HENHMETAFILE m_mfhndl = NULL;

m_hrefdc = CreateDC("DISPLAY", NULL, NULL, NULL);
m_hmfdc = CreateEnhMetaFile(m_hrefdc, NULL, &m_refrect, "Test Metafile");

hpal = CreatePalette( plogp );
SelectPalette( m_hmfdc, hpal, FALSE );

RealizePalette( m_hmfdc );

( perform GDI commands on metafile )

m_mfhndl = CloseEnhMetaFile(m_hmfdc);

( Use metafile )

// release the metafile handle, same handle that was
// returned earlier
DeleteEnhMetaFile(m_mfhndl);

//destroy all created and not any more needed GDI objects
DeleteObject( hpal );
DeleteDC(m_hrefdc);
 
Regards,
Ete

Not the solution you were looking for? Getting a personalized solution is easy.

Ask the Experts

Author

Commented:
You're right. As soon as the CloseEnhMetafile(...) function has been called it is possible to delete the palette object. Thanks for the help.
Access more of Experts Exchange with a free account
Thanks for using Experts Exchange.

Create a free account to continue.

Limited access with a free account allows you to:

  • View three pieces of content (articles, solutions, posts, and videos)
  • Ask the experts questions (counted toward content limit)
  • Customize your dashboard and profile

*This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

OR

Please enter a first name

Please enter a last name

8+ characters (letters, numbers, and a symbol)

By clicking, you agree to the Terms of Use and Privacy Policy.