If you create a temporary CPen object on the stack with one of the one-step CPen constructors,
you can easily forget to deselect the pen from the device context before it goes out of scope.
In that case, although stepping through the code and running BoundsChecker will make you believe
otherwise, this causes a serious GDI resource leak. The CAutoPen class overcomes this flaw and
also selects the pen into the device context in the constructors. MFC is a much too thin wrapper
around Win32!!!
Example of the usage of a CAutoPen (and a CAutoBrush):
void CMyView::OnDraw(CDC* pDC)
{
CAutoPen NewPen(pDC, PS_SOLID, 1, RGB(255,0,0));
CAutoBrush NewBrush(pDC, RGB(0, 255, 0));
CRect rect(10, 10, 110, 110);
pDC->Rectangle(&rect);
}
Source code of CAutoPen and CAutoBrush:
#if !defined AUTOPEN_H
#define AUTOPEN_H
class CAutoPen : public CPen
{
public:
CAutoPen(CDC *pDC, int nPenStyle, int nWidth, COLORREF crColor) :
CPen(nPenStyle, nWidth, crColor), m_pDC(pDC), m_pOldGdi(NULL)
{
Initialize();
}
CAutoPen(CDC *pDC, int nPenStyle, int nWidth, const LOGBRUSH *pLogBrush,
int nStyleCount = 0, const DWORD *lpStyle = NULL) :
CPen(nPenStyle, nWidth, pLogBrush, nStyleCount, lpStyle), m_pDC(pDC), m_pOldGdi(NULL)
{
Initialize();
}
virtual ~CAutoPen()
{
ASSERT_VALID(m_pOldGdi);
ASSERT_VALID(m_pDC);
m_pDC->SelectObject(m_pOldGdi);
}
private:
CDC *m_pDC; CGdiObject *m_pOldGdi;
CAutoPen() { }
void Initialize()
{
m_pOldGdi = m_pDC->SelectObject(this);
ASSERT_VALID(m_pOldGdi);
}
};
class CAutoBrush : public CBrush
{
public:
CAutoBrush(CDC *pDC, COLORREF crColor) :
CBrush(crColor), m_pDC(pDC), m_pOldGdi(NULL)
{
Initialize();
}
CAutoBrush(CDC *pDC, int nIndex, COLORREF crColor) :
CBrush(nIndex, crColor), m_pDC(pDC), m_pOldGdi(NULL)
{
Initialize();
}
CAutoBrush(CDC *pDC, CBitmap* pBitmap) :
CBrush(pBitmap), m_pDC(pDC), m_pOldGdi(NULL)
{
Initialize();
}
virtual ~CAutoBrush()
{
ASSERT_VALID(m_pOldGdi);
ASSERT_VALID(m_pDC);
m_pDC->SelectObject(m_pOldGdi);
}
private:
CDC *m_pDC; CGdiObject *m_pOldGdi;
CAutoBrush() { }
void Initialize()
{
m_pOldGdi = m_pDC->SelectObject(this);
ASSERT_VALID(m_pOldGdi);
}
};
#endif