之前接触MFC比较少,最近一个程序需要使用MFC写界面。写完之后发现程序运行一段时间后异常卡顿,并且Win7系统任务栏图标出现一些毛边等异常情况。重新运行程序,打开任务管理器发现GDI对象不断增加,且数量到达9999后程序开始异常。因此判断程序可能存在GDI对象泄漏,即创建的GDI对象没有及时释放。 鉴于GDI对象不断自动增加,判断GDI泄漏可能位于定时器触发的OnTimer函数中。OnTimer函数调用方法如下:
LRESULT CVServerView::OnChangeTime(WPARAM wParam, LPARAM lParam) { CString strText; FormatTime((INT)wParam, 30, strText); m_editPush.SetWindowText(strText); return 0; }可以看出函数仅仅是调用了API函数SetWindowText,理论上不应该导致GDI泄漏。但奇怪的是注释掉SetWindowText后程序就正常了。后来发现原因在于程序重写了OnCtlColor函数。
HBRUSH CVServerView::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor){ HBRUSH hbr = CFormView::OnCtlColor(pDC, pWnd, nCtlColor); // TODO: 在此更改 DC 的任何特性 if (pWnd->GetDlgCtrlID() == IDC_EDIT_PUSH) { pDC->SetBkMode(TRANSPARENT); pDC->SetTextColor(RGB(255, 255, 255)); return HBRUSH(CreateSolidBrush(RGB(56, 56, 56))); } // TODO: 如果默认的不是所需画笔,则返回另一个画笔 return hbr;}SetWindowText函数会调用以上OnCtlColor函数。OnCtlColor中CreateSolidBrush创建了GDI对象没有释放导致GDI对象不断增加,这就是问题所在。因此将程序修改为创建一个全局画笔m_brushBack=CreateSolidBrush(RGB(56, 56, 56)),OnDestroy时释放掉。修改代码如下:
HBRUSH CVServerView::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor){ HBRUSH hbr = CFormView::OnCtlColor(pDC, pWnd, nCtlColor); // TODO: 在此更改 DC 的任何特性 if (pWnd->GetDlgCtrlID() == IDC_EDIT_PUSH) { pDC->SetBkMode(TRANSPARENT); pDC->SetTextColor(RGB(255, 255, 255)); return HBRUSH(m_brushBack); } // TODO: 如果默认的不是所需画笔,则返回另一个画笔 return hbr;}回头再看,问题很简单并且出现在细节地方,主要原因在于自己对GDI对象管理了解太少,随意创建GDI对象不及时释放。以此提醒自己需要牢记GDI对象创建及释放问题。
新闻热点
疑难解答