CPaintDC resource
-
I have an OnPaint function and it's being called over and over and after a while, it throws a resource exception by simply saying:
A required resource was unavailable.
I have no idea what that means beyond what it says but it's happening sometime in the OnPaint function after it's run a couple thousand times. I only get the "CPaintDC dc(this);" at the top of the try block (to catch exceptions) and then I draw or not draw with if statements later. Am I allocating the drawing context without deallocating it, do I need to release the 'dc' variable or something to the system? Under the CPaintDC constructor, it says this as a remark:
An exception (of type CResourceException) is thrown if the Windows GetDC call fails. A device context may not be available if Windows has already allocated all of its available device contexts. Your application competes for the five common display contexts available at any given time under Windows.
Is that affecting me? If so, how I do rectify this?
-
I have an OnPaint function and it's being called over and over and after a while, it throws a resource exception by simply saying:
A required resource was unavailable.
I have no idea what that means beyond what it says but it's happening sometime in the OnPaint function after it's run a couple thousand times. I only get the "CPaintDC dc(this);" at the top of the try block (to catch exceptions) and then I draw or not draw with if statements later. Am I allocating the drawing context without deallocating it, do I need to release the 'dc' variable or something to the system? Under the CPaintDC constructor, it says this as a remark:
An exception (of type CResourceException) is thrown if the Windows GetDC call fails. A device context may not be available if Windows has already allocated all of its available device contexts. Your application competes for the five common display contexts available at any given time under Windows.
Is that affecting me? If so, how I do rectify this?
It sounds to me like your paint handler is leaking resources. Could you post the code ? Do you clean up the brushes/bitmaps/DCs etc that you use ? Christian Graus - Microsoft MVP - C++
-
It sounds to me like your paint handler is leaking resources. Could you post the code ? Do you clean up the brushes/bitmaps/DCs etc that you use ? Christian Graus - Microsoft MVP - C++
The code is complex, but here's the short of it:
try { CPaintDC dc(this); if ((thread == NULL) && (files != NULL)) { dc.Rectangle(x, y, x + 300, y + nTextHeight + 4); COLORREF OldColor = dc.SetTextColor (RGB(192, 192, 192)); dc.SelectObject (new CBrush(RGB(192, 192, 192))); sMsg.Format("%s, %s", obj->GetName(), obj->GetStringFilesize()); dc.TextOut(x + 2, y + 2, (LPCTSTR) sMsg); dc.SetTextColor(OldColor); dc.SelectObject (new CBrush (RGB(255, 255, 255))); } <2 more sections like the above exist with different if statement tests> } catch (CResourceException * e) { e->Delete(); thread->SuspendThread(); char * lpszMessage = new char[128]; e->GetErrorMessage(lpszMessage, 128, NULL); MessageBox(lpszMessage, "Critical Error", MB_ICONSTOP); delete[] lpszMessage; thread->ResumeThread(); }
That's the gist (and most complex) part of it. I have 3 blocks like the if statement above, the first two are rarely used, but the third is heavily used when a particular thread is running. The heavily used if statement is similar in layout to the above but it draws a text element and pie, both correspond to a progress display of the thread the code mentions. I was handling the CBrush's by new'ing and delete'ing them manually but it threw runtime errors when delete'ing the CBrush's, it said a "pure virtual function call" or something like that. I don't do any clean up, I just get the dc from CPaintDC and then draw, that's it. I figured I didn't need to deallocate the drawing context because I was using it in this method, instead of using a handle to a drawing context with GetDC/ReleaseDC. -
The code is complex, but here's the short of it:
try { CPaintDC dc(this); if ((thread == NULL) && (files != NULL)) { dc.Rectangle(x, y, x + 300, y + nTextHeight + 4); COLORREF OldColor = dc.SetTextColor (RGB(192, 192, 192)); dc.SelectObject (new CBrush(RGB(192, 192, 192))); sMsg.Format("%s, %s", obj->GetName(), obj->GetStringFilesize()); dc.TextOut(x + 2, y + 2, (LPCTSTR) sMsg); dc.SetTextColor(OldColor); dc.SelectObject (new CBrush (RGB(255, 255, 255))); } <2 more sections like the above exist with different if statement tests> } catch (CResourceException * e) { e->Delete(); thread->SuspendThread(); char * lpszMessage = new char[128]; e->GetErrorMessage(lpszMessage, 128, NULL); MessageBox(lpszMessage, "Critical Error", MB_ICONSTOP); delete[] lpszMessage; thread->ResumeThread(); }
That's the gist (and most complex) part of it. I have 3 blocks like the if statement above, the first two are rarely used, but the third is heavily used when a particular thread is running. The heavily used if statement is similar in layout to the above but it draws a text element and pie, both correspond to a progress display of the thread the code mentions. I was handling the CBrush's by new'ing and delete'ing them manually but it threw runtime errors when delete'ing the CBrush's, it said a "pure virtual function call" or something like that. I don't do any clean up, I just get the dc from CPaintDC and then draw, that's it. I figured I didn't need to deallocate the drawing context because I was using it in this method, instead of using a handle to a drawing context with GetDC/ReleaseDC.LighthouseJ wrote:
dc.SelectObject (new CBrush(RGB(192, 192, 192)));
This is a resource leak. you need to create a brush as a variable, and when you call selectobject, you need to grab the brush it returns. Then you need to restore the original brush, and destroy the brush you created.
LighthouseJ wrote:
dc.SelectObject (new CBrush (RGB(255, 255, 255)));
Ditto. I assume this is supposed to restore the original brush color, but you need to actually restore the original brush. Christian Graus - Microsoft MVP - C++
-
LighthouseJ wrote:
dc.SelectObject (new CBrush(RGB(192, 192, 192)));
This is a resource leak. you need to create a brush as a variable, and when you call selectobject, you need to grab the brush it returns. Then you need to restore the original brush, and destroy the brush you created.
LighthouseJ wrote:
dc.SelectObject (new CBrush (RGB(255, 255, 255)));
Ditto. I assume this is supposed to restore the original brush color, but you need to actually restore the original brush. Christian Graus - Microsoft MVP - C++
I actually did that originally but I got the aforementioned error because I was trying to free memory from another threads heap. I changed it like below and no error shows up so I guess it's cleared up but I have to clean up the code more because it was opened up to try and fix this with other methods.
CBrush * grey = new CBrush (RGB(192, 192, 192)); CBrush * black = new CBrush (RGB(255, 255, 255)); dc.SelectObject (grey); < drawing done here > dc.SelectObject(black); delete grey; delete black;
-
I actually did that originally but I got the aforementioned error because I was trying to free memory from another threads heap. I changed it like below and no error shows up so I guess it's cleared up but I have to clean up the code more because it was opened up to try and fix this with other methods.
CBrush * grey = new CBrush (RGB(192, 192, 192)); CBrush * black = new CBrush (RGB(255, 255, 255)); dc.SelectObject (grey); < drawing done here > dc.SelectObject(black); delete grey; delete black;
LighthouseJ wrote:
I actually did that originally but I got the aforementioned error because I was trying to free memory from another threads heap.
Well, it's the way it needs to be done, you need to work out those threading issues, I guess..
LighthouseJ wrote:
CBrush * grey = new CBrush (RGB(192, 192, 192)); CBrush * black = new CBrush (RGB(255, 255, 255)); dc.SelectObject (grey); < drawing done here > dc.SelectObject(black); delete grey; delete black;
This is wrong. CBrush * grey = new CBrush (RGB(192, 192, 192)); CBrush * black = dc.SelectObject (grey); < drawing done here > dc.SelectObject(black); delete grey; You need to grab the brush that SelectObject returns, and put it back when you're done. Christian Graus - Microsoft MVP - C++
-
LighthouseJ wrote:
I actually did that originally but I got the aforementioned error because I was trying to free memory from another threads heap.
Well, it's the way it needs to be done, you need to work out those threading issues, I guess..
LighthouseJ wrote:
CBrush * grey = new CBrush (RGB(192, 192, 192)); CBrush * black = new CBrush (RGB(255, 255, 255)); dc.SelectObject (grey); < drawing done here > dc.SelectObject(black); delete grey; delete black;
This is wrong. CBrush * grey = new CBrush (RGB(192, 192, 192)); CBrush * black = dc.SelectObject (grey); < drawing done here > dc.SelectObject(black); delete grey; You need to grab the brush that SelectObject returns, and put it back when you're done. Christian Graus - Microsoft MVP - C++
I was trying to capture the outgoing brush but when I delete it, I got the error saying the memory I was deallocating wasn't mine. So, I just don't delete the black brush? Isn't that leaking memory?
-
I was trying to capture the outgoing brush but when I delete it, I got the error saying the memory I was deallocating wasn't mine. So, I just don't delete the black brush? Isn't that leaking memory?
LighthouseJ wrote:
I was trying to capture the outgoing brush but when I delete it, I got the error saying the memory I was deallocating wasn't mine.
Correct. You can't delete it, you need to select it back into the DC in order to avoid a leak.
LighthouseJ wrote:
So, I just don't delete the black brush? Isn't that leaking memory?
No, because you don't create a black brush, and because the brush in question is left in the control of the DC, as it was at the start. Christian Graus - Microsoft MVP - C++
-
The code is complex, but here's the short of it:
try { CPaintDC dc(this); if ((thread == NULL) && (files != NULL)) { dc.Rectangle(x, y, x + 300, y + nTextHeight + 4); COLORREF OldColor = dc.SetTextColor (RGB(192, 192, 192)); dc.SelectObject (new CBrush(RGB(192, 192, 192))); sMsg.Format("%s, %s", obj->GetName(), obj->GetStringFilesize()); dc.TextOut(x + 2, y + 2, (LPCTSTR) sMsg); dc.SetTextColor(OldColor); dc.SelectObject (new CBrush (RGB(255, 255, 255))); } <2 more sections like the above exist with different if statement tests> } catch (CResourceException * e) { e->Delete(); thread->SuspendThread(); char * lpszMessage = new char[128]; e->GetErrorMessage(lpszMessage, 128, NULL); MessageBox(lpszMessage, "Critical Error", MB_ICONSTOP); delete[] lpszMessage; thread->ResumeThread(); }
That's the gist (and most complex) part of it. I have 3 blocks like the if statement above, the first two are rarely used, but the third is heavily used when a particular thread is running. The heavily used if statement is similar in layout to the above but it draws a text element and pie, both correspond to a progress display of the thread the code mentions. I was handling the CBrush's by new'ing and delete'ing them manually but it threw runtime errors when delete'ing the CBrush's, it said a "pure virtual function call" or something like that. I don't do any clean up, I just get the dc from CPaintDC and then draw, that's it. I figured I didn't need to deallocate the drawing context because I was using it in this method, instead of using a handle to a drawing context with GetDC/ReleaseDC.Have a look at CDC::SaveDC() ( There is also an excellent article by Joe Newcomer on this site about SaveDC(), look it up ) and also why not just use local GDI objects that go out of scope when you are done with them? saves having to mess around with new and delete.
"You're obviously a superstar." - Christian Graus about me - 12 Feb '03 "Obviously ??? You're definitely a superstar!!!" - mYkel - 21 Jun '04 "There's not enough blatant self-congratulatory backslapping in the world today..." - HumblePie - 21 Jun '05 Within you lies the power for good - Use it!
-
Have a look at CDC::SaveDC() ( There is also an excellent article by Joe Newcomer on this site about SaveDC(), look it up ) and also why not just use local GDI objects that go out of scope when you are done with them? saves having to mess around with new and delete.
"You're obviously a superstar." - Christian Graus about me - 12 Feb '03 "Obviously ??? You're definitely a superstar!!!" - mYkel - 21 Jun '04 "There's not enough blatant self-congratulatory backslapping in the world today..." - HumblePie - 21 Jun '05 Within you lies the power for good - Use it!
I'll read that tonight. I haven't optimized the program for space and efficiency yet but one thing I did was to put the grey brush into the child view to be created once on construction, then used repeatedly, and deleted on deconstruction. I also have to figure out a better flow to my program but that's on my shoulders. I'm trying to optimize drawing because it's definitely the slowest part of my program.