C++ C++;COM、Direct2D、Win32和WM_关闭
在一系列的情况下,我得到了一个非常具体的清理崩溃,我完全不知道发生了什么,所以我只描述一下条件/程序以及它在做什么 我有一个win32程序,使用Direct2D在黑屏上绘制测试字符串和测试位图。一切正常。没有崩溃,没有内存泄漏。但是,只有当我通过以下方式退出该程序时,才能:C++ C++;COM、Direct2D、Win32和WM_关闭,c++,winapi,com,direct2d,C++,Winapi,Com,Direct2d,在一系列的情况下,我得到了一个非常具体的清理崩溃,我完全不知道发生了什么,所以我只描述一下条件/程序以及它在做什么 我有一个win32程序,使用Direct2D在黑屏上绘制测试字符串和测试位图。一切正常。没有崩溃,没有内存泄漏。但是,只有当我通过以下方式退出该程序时,才能: case WM_KEYDOWN: if (wParam == VK_ESCAPE) PostQuitMessage(0); // close program break; 这反过来导致我的消
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();
这很有效。不起作用的是,如果我在调用WM_QUIT的窗口上单击红色的“X”,我不会处理它(而且不应该有理由这样做)。当这种情况发生时,我的消息循环仍然会结束,我的应用程序会调用Delete(),但它会在D2D对象发布时崩溃。顺序无关紧要,它似乎并不依赖于任何其他现有的或正在发布/未发布的内容。我的iWicMagingFactory*无法在不崩溃的情况下发布,即使我没有加载我的图像
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);
}
D2D::~D2D()
{
//释放所有位图
对于(列表::迭代器iter=m_vSprites.begin();iter!=m_vSprites.end();++iter)
{
安全释放(&(iter->m_pImage));
}
SafeRelease(&m_pWICFactory);//单击“红色X”不会生成WM_QUIT
,而是生成WM_CLOSE
。如果您的消息循环没有处理该消息并将其传递到DefWindowProc
,那么您的主窗口将被销毁,然后生成WM_DESTROY
这是窗口销毁的“正常”流程-WM_CLOSE
,WM_DESTROY
,PostQuitMessage
,消息循环结束
相反,如果你自己发布WM_QUIT
消息,你就会立即跳出消息循环,让你的窗口和其他一切都完好无损
这本身没有什么问题,只要你已经编码来处理它,但是通过允许DefWindowProc
处理一个正常的窗口破坏,当你从消息循环中出来时,你不知道你的窗口是否存在,我怀疑这是第二种情况导致了错误我们的问题
我建议更改按escape键时发生的情况-在窗口中发布一条WM\u CLOSE
消息,然后对该消息和WM\u DESTROY
执行处理,以便始终以相同的受控方式退出消息循环
此外,您的消息循环结构不正确,如果它恰好是peek消息
循环检索到的最后一条消息,则当前只会看到WM_QUIT
,否则,您将完全错过它。您可能想要这样的信息:
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;
单击“红色X”不会生成WM\u QUIT
,而是生成WM\u CLOSE
。如果您的消息循环没有处理该消息并将其传递给DefWindowProc
,那么您的主窗口将被销毁,然后生成WM\u DESTROY
这是窗口销毁的“正常”流程-WM_CLOSE
,WM_DESTROY
,PostQuitMessage
,消息循环结束
相反,如果你自己发布WM_QUIT
消息,你就会立即跳出消息循环,让你的窗口和其他一切都完好无损
这本身没有什么问题,只要你已经编码来处理它,但是通过允许DefWindowProc
处理一个正常的窗口破坏,当你从消息循环中出来时,你不知道你的窗口是否存在,我怀疑这是第二种情况导致了错误我们的问题
我建议更改按escape键时发生的情况-在窗口中发布一条WM\u CLOSE
消息,然后对该消息和WM\u DESTROY
执行处理,以便始终以相同的受控方式退出消息循环
此外,您的消息循环结构不正确,如果它恰好是peek消息
循环检索到的最后一条消息,则当前只会看到WM_QUIT
,否则,您将完全错过它。您可能想要这样的信息:
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;
这不仅是要做的正确的事情,也是必须要做的事情。WIC要求COM进行初始化。唯一的谜题是为什么程序在没有它的情况下运行。让我们不用担心。这不仅是要做的正确的事情,也是必须要做的事。WIC要求COM进行初始化。唯一的谜题是为什么程序在没有它的情况下运行我不需要它。我们不用担心。非常感谢。按照您的建议,这似乎是我对windows消息(主要是我不了解QUIT、CLOSE和DESTROY的关系/顺序)理解的问题,而不是COM。这正是您所说的,关闭导致了DestroyWindow()(默认情况下)这导致窗口在我的D2D清理代码之前被破坏。我通过允许WM_CLOSE案例在WndProc开关中进入WM_DESTROY来修复它。另外感谢关于消息循环错误的注释。为了进一步说明,我也通过不处理WM_DESTROY来修复它,而将我的清理代码放入WM_CLOSE中我觉得这更正确,因为微软的WM_CLOSE的目的似乎是“嘿,这个窗口就要被破坏了。你想事先做点什么吗?”虽然消息循环后的清理是愚蠢的。你所做的事情本身并没有错。Windows可以在消息循环开始之前存在,所以没有理由在消息循环退出后无法保持。你只需要确保不管关闭是如何启动的,你都能始终如一地处理它。无论如何,很高兴它现在对你起作用了!继续在COM方面,我很好奇为什么我的D2D在没有初始化COM的情况下工作。但是,为了防止启动时出现win32后台绘图,