C++ C++;COM、Direct2D、Win32和WM_关闭

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; 这反过来导致我的消

在一系列的情况下,我得到了一个非常具体的清理崩溃,我完全不知道发生了什么,所以我只描述一下条件/程序以及它在做什么

我有一个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();
这很有效。不起作用的是,如果我在调用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后台绘图,