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崩溃,请参阅图片。 UI crash

当然,您可以理解这段代码只是一个演示,我的真实业务需要像这样调用CreateIconFromResource几千次。根据Hans的建议,我继续跟踪Handles/USER Objects/GDI对象,发现USER对象增长1000,而GDI对象增长2000对每次点击OK按钮(手柄没有增长),并且当问题发生时GDI对象是9999。但是当我完成使用时,如何正确释放它们?我一次没有使用太多,但需要加载,释放,再次加载,再次释放......就像这个演示。作为MSDN文档,我为每个HICON调用了DestroyIcon。我还需要做什么,最终释放USER/GDI对象?

+0

您可能泄漏手柄,当您泄漏10,000个手表时,节目结束。 –

+0

@Hans,谢谢你的建议,我发现它是USER/GDI对象泄漏的,但我仍然有问题,在我的文章中更新。 – zhiyazw

我找到了答案。成功或失败都归功于MSDN。

它说:

的CreateIconFromResource函数调用CreateIconFromResourceEx传递LR_DEFAULTSIZE | LR_SHARED为标志” AND “不要使用此功能(DestroyIcon)摧毁一个共享图标

但还说:

当您完成使用该图标时,使用CreateIconFromResource文档中的DestroyIcon函数”将其销毁。

其实第二种说法是错误的。

因此,解决方案是,使用CreateIconFromResourceEx而不使用LR_SHARED,并使用每个HICON的DestroyIcon。