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
): <!-- start a block of source code -->
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
: <!-- start a block of source code -->
#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
License
This article has no explicit license attached to it, but may contain usage terms in the article text or the download files themselves. If in doubt, please contact the author via the discussion board below.
A list of licenses authors might use can be found here.