Search code examples
winapimfcgdi

Do I need to call SelectObject() to restore a object retreived with GetStockObject()?


I'm using MFC...

When I create a new brush, I know I need to restore the old bush using SelectObject:

CBrush brushFill;
brushFill.CreateSolidBrush(colorFill);
CBrush *oldBrush = pDC->SelectObject(&brushFill);
// Draw something here.
pDC->SelectObject(oldBrush);

However, if I get the brush using GetStockObject(), do I need to to restore it, too?

CBrush *oldBrush = (CBrush *)pDC->SelectObject(GetStockObject(HOLLOW_BRUSH));
// Draw something here.
pDC->SelectObject(oldBrush);

I ask, because that code occasionally crashes. I'm unsure if that's due to me not supposed to save/restore stock items, or my typecast to a CBrush*. If the latter, I'm thinking I should save/restore an HGDIOBJ handle:

HGDIOBJ oldBrush = pDC->SelectObject(GetStockObject(HOLLOW_BRUSH));
// Draw something here.
pDC->SelectObject(oldBrush);

If the former, I wouldn't save/restore the previous object.


Solution

  • You should always 'bracket' any operations on a device context with the SaveDC() and RestoreDC() member functions of the CDC object:

    int DCsave = pDC->SaveDC(); // Saves all (or most) settings and object selections
    // ... Do your drawing operations, etc.
    pDC->RestoreDC(DCsave);     // Restores the saved state and all selected objects
    

    Also, just for info, you may find the SelectStockObject() member a bit easier to use:

    pDC->SelectStockObject(HOLLOW_BRUSH);
    

    Note (from the comment made by IInspectable): Although deselection of the GDI 'Stock Objects' may seem unnecessary (after all, there will be several of these selected by default), other code may be relying on having the previous object (brush, in your case) selected; failure to restore this selection can thus cause that code to fail in ways that are near impossible to track down.