Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. C / C++ / MFC
  4. Owner draw static control and memory leak

Owner draw static control and memory leak

Scheduled Pinned Locked Moved C / C++ / MFC
helpc++htmlgraphicsperformance
7 Posts 2 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • P Offline
    P Offline
    Peter Pearson
    wrote on last edited by
    #1

    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

    T P 3 Replies Last reply
    0
    • P Peter Pearson

      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

      T Offline
      T Offline
      Tomasz Sowinski
      wrote on last edited by
      #2

      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

      P 1 Reply Last reply
      0
      • P Peter Pearson

        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

        T Offline
        T Offline
        Tomasz Sowinski
        wrote on last edited by
        #3

        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

        1 Reply Last reply
        0
        • T Tomasz Sowinski

          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

          P Offline
          P Offline
          Peter Pearson
          wrote on last edited by
          #4

          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

          1 Reply Last reply
          0
          • P Peter Pearson

            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

            P Offline
            P Offline
            Peter Pearson
            wrote on last edited by
            #5

            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
            
            T 1 Reply Last reply
            0
            • P Peter Pearson

              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
              
              T Offline
              T Offline
              Tomasz Sowinski
              wrote on last edited by
              #6

              GetDeviceCaps(CreateCompatibleDC(NULL), LOGPIXELSY) You're creating and leaking two DCs in each OnPaint. Use dc.GetDeviceCaps instead. Tomasz Sowinski -- http://www.shooltz.com

              P 1 Reply Last reply
              0
              • T Tomasz Sowinski

                GetDeviceCaps(CreateCompatibleDC(NULL), LOGPIXELSY) You're creating and leaking two DCs in each OnPaint. Use dc.GetDeviceCaps instead. Tomasz Sowinski -- http://www.shooltz.com

                P Offline
                P Offline
                Peter Pearson
                wrote on last edited by
                #7

                Thanks for that! I'd never have found that. Cheers, Peter

                1 Reply Last reply
                0
                Reply
                • Reply as topic
                Log in to reply
                • Oldest to Newest
                • Newest to Oldest
                • Most Votes


                • Login

                • Don't have an account? Register

                • Login or register to search.
                • First post
                  Last post
                0
                • Categories
                • Recent
                • Tags
                • Popular
                • World
                • Users
                • Groups