Can someone confirm if this sample code from Microsoft fails to restore the custom brush set with SetDCBrushColor
?
case WM_PAINT:
{
hdc = BeginPaint(hWnd, &ps);
// Initializing original object
HGDIOBJ original = NULL;
// Saving the original object
original = SelectObject(hdc,GetStockObject(DC_PEN));
// ...
SelectObject(hdc, GetStockObject(BLACK_PEN));
Rectangle(hdc,0,0,200,200);
SelectObject(hdc, GetStockObject(DC_PEN));
SelectObject(hdc, GetStockObject(DC_BRUSH));
SetDCBrushColor(hdc, RGB(255,0,0));
SetDCPenColor(hdc, RGB(0,0,255));
Rectangle(hdc,100,300,200,400);
SetDCBrushColor(hdc, RGB(0,255,0));
Rectangle(hdc,300,150,500,300);
// Restoring the original object
SelectObject(hdc,original);
}
break;
//...
Paul Watt, and other posters, suggest we use SelectObject
to restore changes to the pen and brush separately, or that we use SaveDC
and RestoreDC
.
https://www.codeproject.com/Articles/224754/Guide-to-Win32-Memory-DC
// Setup paint for first layer.
HGDIOBJ hOldBrush = ::SelectObject(hDC, hBrush);
HGDIOBJ hOldPen = ::SelectObject(hDC, hPen);
HGDIOBJ hOldFont = ::SelectObject(hDC, hFont);
HGDIOBJ hOldMan = ::SelectObject(hDC, hBmp);
// ... Paint a motley display
::SelectObject(hDC, hOldBrush);
::SelectObject(hDC, hOldPen);
::SelectObject(hDC, hOldFont);
::SelectObject(hDC, hOldMan);
Or use SaveDC
and RestoreDC
to make it easy:
// Take a snap-shot of the current state of the DC
//https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-savedc
int SaveDC(
__in HDC hdc, // Handle to the DC
);
// Restore the DC to a previously saved state
int RestoreDC(
__in HDC hdc, // Handle to the DC
__in int nSavedDC // Saved state claim ticket
);
I realize that I need to use DeleteObject
on any brushes/pens I create that are not stock objects.
Did Microsoft forget to use SelectObject
with a previously saved version of the original brush? (Or should Microsoft have used SaveDC
and RestoreDC
?)
Did Microsoft forget to use SelectObject with a previously saved version of the original brush?
I would say: Yes, they did!
In the case of the SetDCPenColor
call, there isn't a problem, as restoring the original (saved) pen will revert the changes made. It seems that the example forgets to save (and subsequently restore) the original brush; if this is a custom brush, then simply restoring the brush colour with SetDCBrushColor
would (IMHO) not be sufficient restoration.
But the issue doesn't end there! The linked example has also 'forgotten' to call EndPaint
! From here:
Each call to BeginPaint must have a corresponding call to the EndPaint function.
Or should Microsoft have used SaveDC and RestoreDC?
For both convenience and code safety, I would say this is the best policy: saving and restoring the entire DC state(s) avoids any issues that may later arise if/when additional changes to the DC are made in future code revisions. Bracketing your code in SaveDC()
and RestoreDC()
calls also has the advantage of restoring font colours, text modes, mapping modes, et cetera.
However, for code that may possibly be executed extremely frequently, saving and restoring only the components you actually change may show performance improvements (especially on older or slower processors).