把对应的按钮替换成系统默认的CButton按钮,程序正常,但是用自绘的CIconButton则会内存泄漏。请帮忙看一下问题出在哪里,谢谢!
class AFX_EXT_CLASS CIconButton : public CButton
{
private:
// CDC m_NormalDC;
// CDC m_DownDC;
// CDC m_DisableDC;
//
// CBitmap m_NormalBmp;
// CBitmap m_DownBmp;
// CBitmap m_DisableBmp;
HDC m_NormalDC;
HDC m_DownDC;
HDC m_DisableDC;
HBITMAP m_NormalBmp;
HBITMAP m_DownBmp;
HBITMAP m_DisableBmp;
int m_InitDC;
int m_btnType;
bool m_bCheck;
// Construction
public:
CIconButton();
bool GetCheck();
void SetCheck(bool iCheck);
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CIconButton)
public:
virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
protected:
virtual void PreSubclassWindow();
//}}AFX_VIRTUAL
// Implementation
public:
void EnableWindow(bool);
void SetButType(int nType);
void LoadBitmaps(UINT nIDBitmapResource,
UINT nIDBitmapResourceSel = 0,
UINT nIDBitmapResourceFocus = 0,
UINT nIDBitmapResourceDisabled = 0 );
virtual ~CIconButton();
// Generated message map functions
protected:
//{{AFX_MSG(CIconButton)
afx_msg void OnPaint();
afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor);
afx_msg void OnLButtonDblClk(UINT nFlags, CPoint point);
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
CIconButton::CIconButton()
{
m_InitDC = FALSE;
m_NormalDC = CreateCompatibleDC(NULL);
m_DisableDC =CreateCompatibleDC(NULL);
m_DownDC = CreateCompatibleDC(NULL);
m_btnType = BT_NORMAL;
m_NormalBmp = NULL;
m_DownBmp = NULL;
m_DisableBmp = NULL;
m_bCheck = 0;
}
CIconButton::~CIconButton()
{
// m_DisableDC.DeleteDC();
// m_DownDC.DeleteDC();
// m_NormalDC.DeleteDC();
//
// m_NormalBmp.DeleteObject();
// m_DownBmp.DeleteObject();
// m_DisableBmp.DeleteObject();
if(!DeleteDC(m_DisableDC))
{
RETAILMSG(1,(TEXT("Delete Disable DC Failed!\n")));
}
if(!DeleteDC(m_DownDC))
{
RETAILMSG(1,(TEXT("Delete Dowm DC Failed!\n")));
}
if(!DeleteDC(m_NormalDC))
{
RETAILMSG(1,(TEXT("Delete Normal DC Failed!\n")));
}
if (m_NormalBmp)
{
if(!DeleteObject(m_NormalBmp))
{
RETAILMSG(1,(TEXT("Delete Normal Bmp Failed!,ErrCode=%d\n"),GetLastError()));
}
}
if (m_DownBmp)
{
if(!DeleteObject(m_DownBmp))
{
RETAILMSG(1,(TEXT("Delete Down Bmp Failed!,ErrCode=%d\n"),GetLastError()));
}
}
if(m_DisableBmp)
{
if(!DeleteObject(m_DisableBmp))
{
RETAILMSG(1,(TEXT("Delete Disable Bmp Failed!,ErrCode=%d\n"),GetLastError()));
}
}
}
BEGIN_MESSAGE_MAP(CIconButton, CButton)
//{{AFX_MSG_MAP(CIconButton)
ON_WM_PAINT()
ON_WM_CTLCOLOR()
//ON_WM_LBUTTONDBLCLK()
ON_WM_LBUTTONDOWN()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CIconButton message handlers
void CIconButton::PreSubclassWindow()
{
// TODO: Add your specialized code here and/or call the base class
// 在此设置按钮样式为自绘按钮
ModifyStyle(0, GetStyle()|BS_OWNERDRAW);
CButton::PreSubclassWindow();
}
void CIconButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
// TODO: Add your code to draw the specified item
CRect rect;
GetClientRect(&rect);
UINT status = lpDrawItemStruct->itemState;
//CClientDC dc(this);
if ( (status & ODS_DISABLED)&&(m_btnType & BT_DISABLE) )
{
BitBlt(lpDrawItemStruct->hDC,0,0,rect.Width(),rect.Height(),m_DisableDC,0,0,SRCCOPY);
}
else if ((status & ODS_SELECTED) ||m_bCheck)
{
BitBlt(lpDrawItemStruct->hDC,0,0,rect.Width(),rect.Height(),m_DownDC,0,0,SRCCOPY);
Sleep(30); //防止快速点击显示不全
}
else
{
BitBlt(lpDrawItemStruct->hDC,0,0,rect.Width(),rect.Height(),m_NormalDC,0,0,SRCCOPY);
}
}
void CIconButton::OnPaint()
{
CPaintDC dc(this); // device context for painting
// TODO: Add your message handler code here
if (m_InitDC)
{
CRect rect;
GetClientRect(&rect);
UINT status = GetState();
if ( (status & ODS_DISABLED)&&(m_btnType & BT_DISABLE) )
{
BitBlt(dc.m_hDC,0,0,rect.Width(),rect.Height(),m_DisableDC,0,0,SRCCOPY);
}
else if ((status & ODS_SELECTED) ||m_bCheck)
{
BitBlt(dc.m_hDC,0,0,rect.Width(),rect.Height(),m_DownDC,0,0,SRCCOPY);
Sleep(30); //防止快速点击显示不全
}
else
{
BitBlt(dc.m_hDC,0,0,rect.Width(),rect.Height(),m_NormalDC,0,0,SRCCOPY);
}
}
// Do not call CButton::OnPaint() for painting messages
}
HBRUSH CIconButton::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
//HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
// TODO: Change any attributes of the DC here
// TODO: Return a different brush if the default is not desired
//return hbr;
//modify lft 2014.4.25 20:02
return (HBRUSH)GetStockObject(NULL_BRUSH); //返回一个透明刷子,
//HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
}
void CIconButton::LoadBitmaps(
UINT nIDBitmapResource,
UINT nIDBitmapResourceSel ,
UINT nIDBitmapResourceFocus ,
UINT nIDBitmapResourceDisabled )
{
// BITMAP TmpBmp;
if (m_NormalBmp )
DeleteObject(m_NormalBmp);
// CRect rect;
// GetClientRect(&rect);
m_NormalBmp = LOADDLLHBMP(nIDBitmapResource);
SelectObject(m_NormalDC,m_NormalBmp);
// m_NormalDC.SetBkColor(RGB(255,255,0));
// m_NormalDC.Rectangle(rect);
if (nIDBitmapResourceSel != 0)
{
if (m_DownBmp )
DeleteObject(m_DownBmp);
m_DownBmp = LOADDLLHBMP(nIDBitmapResourceSel);
SelectObject(m_DownDC,m_DownBmp);
// m_DownDC.SetBkColor(RGB(255,0,0));
// m_DownDC.Rectangle(rect);
m_btnType |= BT_DOWN;
}
if (nIDBitmapResourceDisabled != 0)
{
if (m_DisableBmp )
DeleteObject(m_DisableBmp);
m_DisableBmp = LOADDLLHBMP(nIDBitmapResourceDisabled);
SelectObject(m_DisableDC,m_DisableBmp);
m_btnType |= BT_DISABLE;
}
m_InitDC = TRUE;
}
void CIconButton::SetButType(int nType)
{
m_btnType |= nType;
}
void CIconButton::OnLButtonDblClk(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
//SendMessage(WM_LBUTTONDOWN,0,0);
if(!bLockIconBtn)
{
CButton::OnLButtonDblClk(nFlags, point);
}
}
void CIconButton::OnLButtonDown(UINT nFlags, CPoint point)
{
//SendMessage(WM_LBUTTONDOWN,0,0);
if(!bLockIconBtn)
{
CButton::OnLButtonDown(nFlags,point);
}
}
void CIconButton::EnableWindow(bool bEnable)
{
int style=GetStyle(); //GetWindowLong(GWL_STYLE);
#define WS_DISABLE 0X08000000
if (bEnable)
{
style &= (~WS_DISABLE);
}
else
{
style |=WS_DISABLE;
}
::SetWindowLong(GetSafeHwnd( ),GWL_STYLE,style);
Invalidate();
}
bool CIconButton::GetCheck()
{
return m_bCheck;
}
void CIconButton::SetCheck(bool bCheck)
{
m_bCheck=bCheck;
Invalidate();
}
------解决思路----------------------
SelectObject(m_NormalDC,m_NormalBmp); 是没有保存 OldObj,也就是说没有将 m_NormalBmp 从 DC 中选中,这样的话,Delete 时是无法成功删除它的。可以看 MSDN 中的说明,正在使用的 对象 是无法删除的。
------解决思路----------------------
除了BZ说的问题,我给一点建议。
Invalidate();用redrawwindow代替。wince中有些情况Invalidate会导致内存泄漏,如果你要使用,那么很简单,用个循环多次调用SetCheck或者EnableWindow函数,然后看看内存是否4k的倍数增加就知道。