Link to home
Start Free TrialLog in
Avatar of dregan
dregan

asked on

GDI memory leaks when using Palettes in Metafiles

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 ?
Avatar of nietod
nietod

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.
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
Avatar of dregan

ASKER

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.
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

ASKER CERTIFIED SOLUTION
Avatar of ete
ete

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of dregan

ASKER

You're right. As soon as the CloseEnhMetafile(...) function has been called it is possible to delete the palette object. Thanks for the help.