LoginSignup
5
6

More than 5 years have passed since last update.

[MFC] CDialogでDomodalしたときにすぐにクローズしようとしてASSERTで怒られた件

Posted at

ちょっと細かい話です。

事の経緯

DoModalって普通はユーザに回答を促すダイアログを出したいときに使うので、表題のようなことは起こり得ないんでは…と思われるかもしれませんが、こういう状況は例えば…
「ファイルのコピー中の進捗表示」
などの、進捗表示系ダイアログを作るときに往々にして起こり得ます。

だいたい、進捗表示をやらせる場合は、

  • メイン(UI)スレッドに進捗ダイアログ表示
  • ワーカースレッドで実作業

という形にほぼ落ち着くかと思います。で、ワーカー側からユーザ定義ウィンドウメッセージをダイアログに送って、表示の更新を行うのがセオリーですね。

で、「ワーカーが終わったらダイアログを自動的に閉じたい」という欲求も当然でてきます。普通に組むとそれなりに動いてくれるわけですが、ここで問題があって、ワーカーの処理が早く終わりすぎた等、ダイアログが表示し終わる前にEndDialog等で終わらせるとASSERTが出てしまう…ということです。
ASSERTはデバッグの時しかでないので無視してもいいといえばいいんですが、それでは気持ちが悪いのでなんとかしてみましょうということです。

モードレスダイアログならこういった状況は起きにくいんですが(HIDEで隠してあとで破棄すればよいだけの話)、モードレスの場合はメインウィンドウが触れたりしますよね。それは困るのでモーダルで…と言うことです。

解決方法

色々やってみましたが、結局

  • OnInitDialog でタイマー起動
  • タイマー関数で閉じる要求のフラグを見てここからEndDialog発行
  • ユーザメッセージからのダイアログ閉じる要求は、直接EndDialogを呼び出すのではなく、閉じる要求フラグを立てる

という方法に落ち着きました。多少泥臭いですが仕方なしです。

「メッセージを送るんじゃなくて直接閉じれないの?」と思われがちですが、MFC(かな)は「スレッドが違うもの同士のダイアログは触れてはならない」という面倒くさい鉄の掟があるのでメッセージで…ということでした。

コードにするとこんな感じです。

CxxxDialog.h

#define USER_PROGRESS WM_USER + 0x10

WorkerThread.cpp

// 進捗状況ダイアログを閉じたい
void WorkerThread::CloseWindow(CWnd *pWnd)
{
    pWnd->SendMessage(USER_PROGRESS,0,1);
}


CxxxDialog.cpp

CxxxDialog::CxxxDialog(hogehoge) : hogehoge
{
    m_close = false;
}


BEGIN_MESSAGE_MAP(CxxxDialog, CDialog)
...
    ON_MESSAGE(USER_PROGRESS,&CxxxDialog::OnUserProgress)
    ON_WM_TIMER()
END_MESSAGE_MAP()


BOOL CxxxDialog::OnInitDialog()
{
    // iroiro
    m_TimerID = SetTimer(100,100,NULL);
    // iroiro
}

LRESULT CxxxDialog::OnUserProgress(WPARAM wParam, LPARAM lParam)
{
    // iroiro

    // 仮に、lparamが1の時は閉じる要求があったことにする
    if(lParam == 1){
        m_close = true;
        return 0;
    }
    // iroiro
}

void CxxxDialog::OnTimer(UINT nIDEvent)
{
    // クローズ指示が来た場合、タイマーによってEnddialogを使うことで安全に閉じる
    if(m_close){
        KillTimer(m_TimerID);
        EndDialog(0);
    }
}

5
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
6