0

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

我有一个使用 Direct2D 的 win32 程序在黑屏上绘制测试字符串和测试位图。这一切都有效。没有崩溃,根本没有内存泄漏。但是,只有当我通过以下方式退出程序时:

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 对象时特别崩溃。顺序无关紧要,它似乎不依赖于任何其他现有或正在发布/未发布的内容。即使我不加载图像,我的 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 清理时才有问题?): 在析构函数中调用 Inherited IUnknown::Release()

4

1 回答 1

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;
于 2013-07-03T19:52:03.287 回答