我在一系列情况下得到了一个非常具体的清理崩溃,我完全迷失了发生了什么,所以我只描述条件/程序以及它正在做什么。
我有一个win32程序,使用Direct2D在黑屏上绘制测试字符串和测试位图。一切正常。没有崩溃,没有内存泄漏。但是,只有当我通过以下方式退出程序时才会这样:
case WM_KEYDOWN:
if (wParam == VK_ESCAPE)
PostQuitMessage(0); // close program
break;
这反过来导致我的消息循环结束,调用我的清理代码:
Application app(hWnd);
// message loop
while(true)
{
// Check to see if any messages are waiting in the queue
while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
// Translate the message and dispatch it to WindowProc()
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// If the message is WM_QUIT, exit the while loop
if(msg.message == WM_QUIT)
break;
// runtime code
app.Update();
// continue...
Sleep(FRAME_DELAY);
}
// cleanup code
app.Delete();
有效。什么不起作用是如果我点击窗口上的红色'X'调用我没有处理的WM_QUIT(并且没有理由)。当发生这种情况时,我的消息循环仍然结束,我的应用程序调用Delete(),但它特别崩溃了D2D对象的发布。顺序无关紧要,它似乎不依赖于任何其他存在或被释放/未被释放。即使我没有加载我的图像,我的IWICImagingFactory *也无法在没有崩溃的情况下发布...
D2D::~D2D()
{
// release all bitmaps
for (list<tSprite>::iterator iter = m_vSprites.begin();iter != m_vSprites.end();++iter)
{
SafeRelease(&(iter->m_pImage));
}
SafeRelease(&m_pWICFactory);// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<THIS LINE
SafeRelease(&m_pText);
SafeRelease(&m_pDWFactory);
SafeRelease(&m_pBrush);
SafeRelease(&m_pD2D);
SafeRelease(&m_pD2DFactory);
}
最后我添加了一些代码,这些代码偶然修复了崩溃,但我想知道为什么以及它是否正确。我将应用程序的生命包装在COM初始化/单元调用中:
// init code
CoInitializeEx(0,COINIT_DISABLE_OLE1DDE);//<<<<<<<<<<<<<<
Application app(hWnd);
// message loop
while(true)
...
// cleanup code
app.Delete();
CoUninitialize();//<<<<<<<<<<<<<
总而言之,即使没有COM代码,程序也能正常运行并正常退出,除非我点击红色'X',在这种情况下只有D2D WIC图像工厂无法释放。
类似的问题(只有我的通过WM_CLOSE清理后才会出现问题?): Calling Inherited IUnknown::Release() in a destructor
答案 0 :(得分:3)
点击“红色X”不会生成WM_QUIT
,它会生成WM_CLOSE
。如果您的消息循环没有处理该消息并将其传递给DefWindowProc
,那么您的主窗口将被销毁,然后生成WM_DESTROY
。
这是窗口销毁的“正常”流程 - WM_CLOSE
,WM_DESTROY
,PostQuitMessage
,消息循环结束。
相反,通过自己发布WM_QUIT
,您可以立即突破消息循环,让您的窗口和其他所有内容完好无损。
这没有什么本质上的错误,只要你已经编码来处理它,但是通过允许DefWindowProc
处理正常的窗口破坏你也会创建一个你不知道你的窗口的情况当你走出你的消息循环时,是否存在,我怀疑这是导致你出现问题的第二种情况。
我建议您更改按下转义时发生的情况 - 在您的窗口发布WM_CLOSE
消息,然后对该消息和WM_DESTROY
实施处理,以便始终在同一控制下退出消息循环方式。
此外,您的消息循环结构不正确,目前只会看到WM_QUIT
,如果恰好是PeekMessage
循环要检索的最后一条消息 - 如果不是,您会错过它完全。你可能想要这样的东西:
bool fGotQuit = false;
while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
// If the message is WM_QUIT, exit the while loop
if (fGotQuit = (msg.message == WM_QUIT))
break;
// Translate the message and dispatch it to WindowProc()
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// If the message is WM_QUIT, exit the while loop
if(fGotQuit)
break;