Owner draw static control and memory leak
-
Hi, I've written a very simple custom static control that allows you certain control over formatting via HTML type tags (bold, italic and underlined). I've got it working, but when you drag a window over the control and it gets repainted, the memory usage for the program goes up collosally, which is obviously a memory leak. I've traced the problem to creating the fonts, via CFont, but despite DeleteObjects and just plain deletes of the CFont object/pointer, the memory leak is still there. I'm creating a font every time the WM_PAINT message is called using the CreateFont() function. I've tried saving the old font then restoring the old font at the end but this doesn't help either. Is anyone who knows what they're doing with GDI willing to have a look through the code (180 lines .cpp and .h) if I email it to them, as I really haven't a clue what's wrong. Many thanks, Peter
-
Hi, I've written a very simple custom static control that allows you certain control over formatting via HTML type tags (bold, italic and underlined). I've got it working, but when you drag a window over the control and it gets repainted, the memory usage for the program goes up collosally, which is obviously a memory leak. I've traced the problem to creating the fonts, via CFont, but despite DeleteObjects and just plain deletes of the CFont object/pointer, the memory leak is still there. I'm creating a font every time the WM_PAINT message is called using the CreateFont() function. I've tried saving the old font then restoring the old font at the end but this doesn't help either. Is anyone who knows what they're doing with GDI willing to have a look through the code (180 lines .cpp and .h) if I email it to them, as I really haven't a clue what's wrong. Many thanks, Peter
This is a classic. You're trying to call DeleteObject on a GDI object selected into device context. If you're dealing with font, save the CFont pointer returned SelectObject, and select it back before calling DeleteObject:
CFont f;
f.CreateFont(...);
CFont *pOldFont = dc.SelectObject(&font);
// ... draw
dc.SelectObject(pOldFont);
// GDI font is deleted when f goes out of scope.Tomasz Sowinski -- http://www.shooltz.com
-
Hi, I've written a very simple custom static control that allows you certain control over formatting via HTML type tags (bold, italic and underlined). I've got it working, but when you drag a window over the control and it gets repainted, the memory usage for the program goes up collosally, which is obviously a memory leak. I've traced the problem to creating the fonts, via CFont, but despite DeleteObjects and just plain deletes of the CFont object/pointer, the memory leak is still there. I'm creating a font every time the WM_PAINT message is called using the CreateFont() function. I've tried saving the old font then restoring the old font at the end but this doesn't help either. Is anyone who knows what they're doing with GDI willing to have a look through the code (180 lines .cpp and .h) if I email it to them, as I really haven't a clue what's wrong. Many thanks, Peter
I've just realized that you're already restoring the old font. Sorry for first response - email the code to shooltz@shooltz.com - I'll have a look. Tomasz Sowinski -- http://www.shooltz.com
-
This is a classic. You're trying to call DeleteObject on a GDI object selected into device context. If you're dealing with font, save the CFont pointer returned SelectObject, and select it back before calling DeleteObject:
CFont f;
f.CreateFont(...);
CFont *pOldFont = dc.SelectObject(&font);
// ... draw
dc.SelectObject(pOldFont);
// GDI font is deleted when f goes out of scope.Tomasz Sowinski -- http://www.shooltz.com
Thanks for the tips but it didn't help. I've posted the full OnPaint code under the original thread so maybe that will help? Cheers, Peter
-
Hi, I've written a very simple custom static control that allows you certain control over formatting via HTML type tags (bold, italic and underlined). I've got it working, but when you drag a window over the control and it gets repainted, the memory usage for the program goes up collosally, which is obviously a memory leak. I've traced the problem to creating the fonts, via CFont, but despite DeleteObjects and just plain deletes of the CFont object/pointer, the memory leak is still there. I'm creating a font every time the WM_PAINT message is called using the CreateFont() function. I've tried saving the old font then restoring the old font at the end but this doesn't help either. Is anyone who knows what they're doing with GDI willing to have a look through the code (180 lines .cpp and .h) if I email it to them, as I really haven't a clue what's wrong. Many thanks, Peter
Right here's the OnPaint code:
void CCustStatic::OnPaint()
{
CPaintDC dc(this);CString strText; GetWindowText(strText); CRect rect; GetClientRect(rect); rect.DeflateRect(CSize(1, 1)); dc.FillSolidRect(rect, m\_Colour); int nMode = dc.SetBkMode(TRANSPARENT); if (m\_bSimple == TRUE) { CFont font; font.CreateFont(-MulDiv(m\_nSize, GetDeviceCaps(CreateCompatibleDC(NULL), LOGPIXELSY), 72),0,0,0,m\_nWeight,0,0,0,ANSI\_CHARSET,OUT\_DEFAULT\_PRECIS,CLIP\_DEFAULT\_PRECIS, DEFAULT\_QUALITY, DEFAULT\_PITCH|FF\_DONTCARE, "Arial"); CFont \*oldfont = dc.SelectObject(&font); if (m\_bCentred == TRUE) { CSize Extent = dc.GetTextExtent(strText); CPoint pt(rect.CenterPoint().x - Extent.cx/2, rect.CenterPoint().y - Extent.cy/2); if (!strText.IsEmpty()) { dc.TextOut(pt.x, pt.y, strText); } } else { CRect rect2 = rect; rect2.DeflateRect(CSize(2,2)); dc.DrawText(strText, strText.GetLength(), rect2, DT\_LEFT | DT\_WORDBREAK | DT\_NOPREFIX); } dc.SelectObject(oldfont); } else { int nX, nY = 0; if (m\_bCentred == TRUE) { CString strTextTemp = ""; //= strText; for (int j = 0; j < strText.GetLength(); j++) { if (strText\[j\] == '<') { if (strText\[j + 1\] == '/') { j ++; } j ++; j ++; j ++; } else { strTextTemp += strText\[j\]; } } CFont font; font.CreateFont(-MulDiv(m\_nSize, GetDeviceCaps(CreateCompatibleDC(NULL), LOGPIXELSY), 72),0,0,0,m\_nWeight,0,0,0,ANSI\_CHARSET,OUT\_DEFAULT\_PRECIS,CLIP\_DEFAULT\_PRECIS, DEFAULT\_QUALITY, DEFAULT\_PITCH|FF\_DONTCARE, "Arial"); CFont \*oldfont = dc.SelectObject(&font); CSize Extent = dc.GetTextExtent(strTextTemp); nX = rect.CenterPoint().x - Extent.cx/2; nY = rect.CenterPoint().y - Extent.cy/2; dc.SelectObject(oldfont); } else { nX = rect.left; nY = rect.top; } BOOL bInsideTag = FALSE; BOOL bBold = FALSE; BOOL bItalic = FALSE; BOOL bUnderLined = FALSE; BOOL bEndTag = FALSE; for (int i = 0; i < strText.GetLength(); i++) { if (!bInsideTag) { if (strText\[i\] == '<') { bInsideTag = TRUE; continue; } CFont font; if (bBold == TRUE) { font.CreateFont(-MulDiv(m\_nSize, GetDeviceCaps(CreateCompatibleDC(NULL), LOGPIXELSY), 72), 0, 0, 0, m\_nWeight + 200, bItalic, bUnderLined, 0, ANSI\_CHARSET, OUT\_DEFAULT\_PRECIS, CLIP\_DEFAULT\_PRECIS, DEFAULT\_QU
-
Right here's the OnPaint code:
void CCustStatic::OnPaint()
{
CPaintDC dc(this);CString strText; GetWindowText(strText); CRect rect; GetClientRect(rect); rect.DeflateRect(CSize(1, 1)); dc.FillSolidRect(rect, m\_Colour); int nMode = dc.SetBkMode(TRANSPARENT); if (m\_bSimple == TRUE) { CFont font; font.CreateFont(-MulDiv(m\_nSize, GetDeviceCaps(CreateCompatibleDC(NULL), LOGPIXELSY), 72),0,0,0,m\_nWeight,0,0,0,ANSI\_CHARSET,OUT\_DEFAULT\_PRECIS,CLIP\_DEFAULT\_PRECIS, DEFAULT\_QUALITY, DEFAULT\_PITCH|FF\_DONTCARE, "Arial"); CFont \*oldfont = dc.SelectObject(&font); if (m\_bCentred == TRUE) { CSize Extent = dc.GetTextExtent(strText); CPoint pt(rect.CenterPoint().x - Extent.cx/2, rect.CenterPoint().y - Extent.cy/2); if (!strText.IsEmpty()) { dc.TextOut(pt.x, pt.y, strText); } } else { CRect rect2 = rect; rect2.DeflateRect(CSize(2,2)); dc.DrawText(strText, strText.GetLength(), rect2, DT\_LEFT | DT\_WORDBREAK | DT\_NOPREFIX); } dc.SelectObject(oldfont); } else { int nX, nY = 0; if (m\_bCentred == TRUE) { CString strTextTemp = ""; //= strText; for (int j = 0; j < strText.GetLength(); j++) { if (strText\[j\] == '<') { if (strText\[j + 1\] == '/') { j ++; } j ++; j ++; j ++; } else { strTextTemp += strText\[j\]; } } CFont font; font.CreateFont(-MulDiv(m\_nSize, GetDeviceCaps(CreateCompatibleDC(NULL), LOGPIXELSY), 72),0,0,0,m\_nWeight,0,0,0,ANSI\_CHARSET,OUT\_DEFAULT\_PRECIS,CLIP\_DEFAULT\_PRECIS, DEFAULT\_QUALITY, DEFAULT\_PITCH|FF\_DONTCARE, "Arial"); CFont \*oldfont = dc.SelectObject(&font); CSize Extent = dc.GetTextExtent(strTextTemp); nX = rect.CenterPoint().x - Extent.cx/2; nY = rect.CenterPoint().y - Extent.cy/2; dc.SelectObject(oldfont); } else { nX = rect.left; nY = rect.top; } BOOL bInsideTag = FALSE; BOOL bBold = FALSE; BOOL bItalic = FALSE; BOOL bUnderLined = FALSE; BOOL bEndTag = FALSE; for (int i = 0; i < strText.GetLength(); i++) { if (!bInsideTag) { if (strText\[i\] == '<') { bInsideTag = TRUE; continue; } CFont font; if (bBold == TRUE) { font.CreateFont(-MulDiv(m\_nSize, GetDeviceCaps(CreateCompatibleDC(NULL), LOGPIXELSY), 72), 0, 0, 0, m\_nWeight + 200, bItalic, bUnderLined, 0, ANSI\_CHARSET, OUT\_DEFAULT\_PRECIS, CLIP\_DEFAULT\_PRECIS, DEFAULT\_QU
GetDeviceCaps(CreateCompatibleDC(NULL), LOGPIXELSY) You're creating and leaking two DCs in each OnPaint. Use dc.GetDeviceCaps instead. Tomasz Sowinski -- http://www.shooltz.com
-
GetDeviceCaps(CreateCompatibleDC(NULL), LOGPIXELSY) You're creating and leaking two DCs in each OnPaint. Use dc.GetDeviceCaps instead. Tomasz Sowinski -- http://www.shooltz.com
Thanks for that! I'd never have found that. Cheers, Peter