Re: Leaking GDI handles
Hi
my code which is long
CWnd *pwnd = AfxGetMainWnd();
CWindowDC dc(pwnd); // screen DC--I won't actually draw on it
int idc = dc.SaveDC();
CDC cdcSave;
RECT rect, rectorg;
RECT rectCompatible;
CDC hdcCompatible;
rect.left = p.x-2;
rect.right = p.x + __iinticonsize +4;
rect.top = p.y -2;
rect.bottom = p.y +__iinticonsize +4;
//save screen in rectangel------------------------------------------
rectorg.left = p.x-2;
rectorg.right = p.x + w - 6;//p.x+36
rectorg.top = p.y -2;
rectorg.bottom = p.y + h - 6; //p.y+36
//I see at least 2 Handle leaks here:
cdcSave.CreateDC("DISPLAY", NULL, NULL, NULL);
int icdcSave = cdcSave.SaveDC();
//if first create global restore data
if (_iflgbmpfirst) {
_iflgbmpfirst = EFLGFAL;
_cdcSave.CreateCompatibleDC(NULL);
HBITMAP hbmSave = CreateCompatibleBitmap(dc, w+2, h+2);
originalhbmSave = SelectObject(_cdcSave, hbmSave);
if (!originalhbmSave) {
AfxMessageBox("Bitmap error", MB_OK);
}
}
//save picture and position below of the area we want to
//draw enlarged button in
_cdcSave.BitBlt(0,0,w,h,&cdcSave,rectorg.left,rectorg.top,SRCCOPY);
_xPos = rectorg.left;
_yPos = rectorg.top;
//
rectCompatible.left = 0;
rectCompatible.right = __iintbtnsize;
rectCompatible.top = 0;
rectCompatible.bottom = __iintbtnsize;
_iflgbltsave = EFLGTRU;
//create memory DC to do the drawing in
hdcCompatible.CreateCompatibleDC(NULL);
MICINT ihdcCompatible = hdcCompatible.SaveDC();
HBITMAP hbmScreen =
CreateCompatibleBitmap(dc, __iintbtnsize,
__iintbtnsize);
originalhbmScreen = SelectObject(hdcCompatible, hbmScreen);
if (!originalhbmScreen) {
AfxMessageBox("Bitmap error", MB_OK);
}
PxLib::FillRect(hdcCompatible, &rectCompatible,
GetSysColor(COLOR_3DLIGHT));
RECT rr;
rr.left=rectCompatible.left;
rr.right=rectCompatible.right;
rr.top=rectCompatible.top;
rr.bottom=rectCompatible.bottom;
hdcCompatible.DrawEdge(&rr, BDR_RAISEDINNER, BF_RECT);
m_ilButtons.Draw(&hdcCompatible, iintbtn, CPoint(2,3), iflag_);
cdcSave.StretchBlt(rect.left,rect.top,w,h,&hdcCompatible,0,0,
__iintbtnsize,__iintbtnsize,SRCCOPY);
RECT redge;
redge.left = rect.left;
redge.right = rect.left + w;
redge.top = rect.top;
redge.bottom = rect.top + h;
cdcSave.DrawEdge(&redge, EDGE_ETCHED, BF_RECT); //EDGE_ETCHED EDGE_RAISED
redge.left = rect.left+1;
redge.right = rect.left + w -1;
redge.top = rect.top + 1;
redge.bottom = rect.top + h -1;
cdcSave.DrawEdge(&redge, BDR_RAISEDINNER, BF_RECT); //EDGE_ETCHED EDGE_RAISED
_icountdraw++;
if (originalhbmSave) {
//SelectObject(_cdcSave, originalhbmSave);
}
if (originalhbmScreen) {
SelectObject(hdcCompatible, originalhbmScreen);
}
DeleteObject(hbmScreen);
hdcCompatible.RestoreDC(ihdcCompatible);
hdcCompatible.DeleteDC();
cdcSave.RestoreDC(icdcSave);
cdcSave.DeleteDC();
dc.RestoreDC(idc);
The _cdcSave
is a global DC that i use to save the bitmap in, to restore the screen from
MCCButtonDelete(
int iflgcln_ //< clean up, delete the
) {
if (_iflgbltsave) {
CWnd *pwnd = AfxGetMainWnd();
CWindowDC dc(pwnd); // screen DC--I won't actually draw on it
int save = dc.SaveDC();
int h,w;
h = w = __iintbtnsize * __iintbtnzoomfactor; //42
_iflgbltsave = EFLGFAL;
_icountdraw--;
CDC cdcSave;
cdcSave.CreateDC("DISPLAY", NULL, NULL, NULL);
cdcSave.BitBlt( _xPos, _yPos, w ,h, &_cdcSave,0,0,SRCCOPY);
cdcSave.DeleteDC();
dc.RestoreDC(save);
}
if (iflgcln_) {//clean up
_cdcSave.DeleteDC();
_iflgbmpfirst = EFLGTRU;
}
}
So its weird. I hope you can follow my way to do it, and maybee can give a
solution.
Laurs
"Joseph M. Newcomer" wrote:
The most common cause of losing handles is to delete an object while it is still selected
into a DC. The most common cause of this in MFC is
... stuff here
CPen red(...stuff here...);
dc.SelectObject(&red);
...do some drawing
}
Note that ~CPen is called while the pen is still selected. What happens is that when
~CPen is called, it calls CGDIObject::DeleteObject which calls ::DeleteObject on the
handle of the object. But if the object is selected into a DC, the object is not deleted,
and therefore leaks.
Key here is to either select the original pen back in
CPen * oldPen = dc.SelectObject(&red);
... do some drawing
dc.SelectObject(oldPen);
or better still, use SaveDC/RestoreDC:
int save = dc.SaveDC();
... stuff
CPen red(...);
dc.SelectObject(&red);
... drawing
dc.RestoreDC(save);
the RestoreDC restores the DC to its saved state, thus deselecting the pen, so when the
destructor is called, the object is actually deleted.
This is the most common cause I've seen of GDI resource leaks in MFC code. The same error
applies in raw Win32 programming, e.g.,
HPEN pen;
pen = CreatePen(PS_SOLID, 0, RGB(...));
SelectObject(dc, pen);
... drawing
DeleteObject(pen);
which is actually what the MFC code I showed is doing. So look for those situations
first.
joe
On Tue, 2 Dec 2008 06:26:07 -0800, Laurs <Laurs@discussions.microsoft.com> wrote:
Hi
I have a problem with Leaking GDI handles (in a MFC environment mixed with
CCoolMenuManager).
My goal is to show a zoomed button from the toolbar just to the left of the
mouse cursor when the user holds the mouse over the button.
When the user moves the cursor, the screen behind the zoomed button must be
restored and the zoomed button redrawed at the new position.
When the user moves the mouse outside the toolbar, all resources and handles
should be released.
Any hints?
My own implimentation was very bad, but runs until handles are used up.
Every Zooming eats up around 4 GDI handles.
Its done with dc, bitmap, bitblt, draw, drawedge, selectobject and I am so
ashamed that I will not copy the code hereto (now).
Joseph M. Newcomer [MVP]
email: newcomer@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm