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();

それはうまくいきます。動作しないのは、ウィンドウの赤い「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/unit 呼び出しにラップしました。

   // 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を介してクリーンアップした場合にのみ問題が発生するのは私だけですか?):デストラクタ で継承されたIUnknown::Release()を呼び出す

4

1 に答える 1

3

「赤い X」をクリックしても は生成されずWM_QUIT、生成されWM_CLOSEます。メッセージ ループがそのメッセージを処理して渡さない場合DefWindowProc、メイン ウィンドウが破棄され、WM_DESTROY.

これは、ウィンドウ破壊の「通常の」フローです - WM_CLOSE, WM_DESTROY, PostQuitMessage, メッセージ ループが終了します。

代わりに、自分自身を投稿するWM_QUITことで、メッセージ ループからすぐに抜け出し、ウィンドウと他のすべてをそのまま残します。

処理するようにコーディングしている限り、これに本質的に問題はありませんがDefWindowProc、通常のウィンドウの破棄を処理できるようにすることで、ウィンドウから出たときにウィンドウが存在するかどうかわからない状況を作成しています。あなたのメッセージループ、そしてあなたの問題を引き起こしているのはこの2番目のケースだと思います.

エスケープを押したときに何が起こるかを変更することをお勧めします。ウィンドウに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 に答える