【已解決】CResourceException 異常處理

最近開發一個自訂控制項,當視窗經過多次放大、縮小後就會產生

First-chance exception at 0x000007fefcfe940d in XXX_x64.exe: Microsoft C++ exception: CResourceException * __ptr64 at memory location 0x0027b360..
First-chance exception at 0x000007fefcfe940d in XXX_x64.exe: Microsoft C++ exception: CInvalidArgException * __ptr64 at memory location 0x00276b90..
Warning: Uncaught exception in WindowProc (returning 0).

經過搜尋的結果,應該是使用資源後未釋放,造成資源耗盡。問題是沒有捕捉到產生異常的地方,要修改也無從下手。於是先用 try catch 在有可能的地方試試看



void ItemView::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{

	// TODO:  Add your code to draw the specified item
	try {
		CDC*	pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
		. . .
	} catch (CResourceException*) {
		TRACE(_T("Happened\n"));
	}
}

把中斷點設在 TRACE,經過操作視窗放大、縮小後,果然就捕捉到了。不過檢查程式碼的結果,並沒有發現未釋放資源的狀況。而且把程式碼註解掉先不要執行,依然在別的地方會產生異常,可見這裡是 "果",而非 "因"。是別的地方將資源耗盡,所以需要取用資源的地方得不到資源就會產生異常了。

經過多方的查證,總算在上層的視窗找到一個可疑的地方

HBRUSH DlgScroll::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
	hbr = CreateSolidBrush(RGB(0, 0, 0));	//black
	return hbr;
}

這裡會一直產生黑色的 Brush,但並沒有釋放掉的機制,所以凶手應該就是它了。更慘的是它不會產生異常,所以 try catch 了半天也捕捉不到。將程式碼改成以下的方式就正常了!

hbr = (HBRUSH)GetStockObject(BLACK_BRUSH);

另外用 資源監視器 (從 工作管理員效能 頁中開啟) 也可以觀看記憶體使用的狀況


到程式 Crash 為止,可以看到工作集記憶體增加了將近 800KB;而正常的版本只有幾 10KB 的上下變動而己。


另外假設 FromHandle 產生異常的話,那程式將直接結束,而不會將結果設定 pDC,所以 ASSERT 也是沒作用的。

	CDC*	pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
	ASSERT(pDC != NULL);

留言

這個網誌中的熱門文章

Linux 批次檔的寫法

【分享】如何顯示 Debug Message

[分享] Visual Studio 遠端偵錯