CreateIconFromResource在被调用数千次后返回NULL和UI崩溃
任何人都有这个问题,无论如何我没有找到答案。代码很简单:CreateIconFromResource在被调用数千次后返回NULL和UI崩溃
void CbDlg::OnBnClickedOk()
{
for(int i=0; i<1000; i++)
{
HRSRC hRes = ::FindResource(NULL, MAKEINTRESOURCE(IDR_MAINFRAME), RT_GROUP_ICON);
HGLOBAL hResLoad = ::LoadResource(NULL, hRes);
BYTE* pIconBytes = (BYTE*)::LockResource(hResLoad);
int nId = ::LookupIconIdFromDirectory(pIconBytes, TRUE);
hRes = ::FindResource(NULL, MAKEINTRESOURCE(nId), RT_ICON);
DWORD read = ::SizeofResource(NULL ,hRes);
hResLoad = ::LoadResource(NULL, hRes);
pIconBytes = (BYTE*)::LockResource(hResLoad);
if(pIconBytes != NULL)
{
HICON hIcon = ::CreateIconFromResource(pIconBytes, read, TRUE, 0x00030000);
DWORD e = ::GetLastError();
if(hIcon != NULL)
{
::DestroyIcon(hIcon);
}
}
}
}
如果我点击确定按钮四次(在我的电脑),CreateIconFromResource开始返回NULL(它之前的工作很好,我甚至可以画出来的图标)。至于GetLastError,无论CreateIconFromResource是否返回NULL,它总是返回6。
当这个问题发生时,如果我拖动标题栏移动,UI崩溃,请参阅图片。
当然,您可以理解这段代码只是一个演示,我的真实业务需要像这样调用CreateIconFromResource几千次。根据Hans的建议,我继续跟踪Handles/USER Objects/GDI对象,发现USER对象增长1000,而GDI对象增长2000对每次点击OK按钮(手柄没有增长),并且当问题发生时GDI对象是9999。但是当我完成使用时,如何正确释放它们?我一次没有使用太多,但需要加载,释放,再次加载,再次释放......就像这个演示。作为MSDN文档,我为每个HICON调用了DestroyIcon。我还需要做什么,最终释放USER/GDI对象?
我找到了答案。成功或失败都归功于MSDN。
它说:
“的CreateIconFromResource函数调用CreateIconFromResourceEx传递LR_DEFAULTSIZE | LR_SHARED为标志” AND “不要使用此功能(DestroyIcon)摧毁一个共享图标”
但还说:
“当您完成使用该图标时,使用CreateIconFromResource文档中的DestroyIcon函数”将其销毁。
其实第二种说法是错误的。
因此,解决方案是,使用CreateIconFromResourceEx而不使用LR_SHARED,并使用每个HICON的DestroyIcon。
您可能泄漏手柄,当您泄漏10,000个手表时,节目结束。 –
@Hans,谢谢你的建议,我发现它是USER/GDI对象泄漏的,但我仍然有问题,在我的文章中更新。 – zhiyazw