モードレスダイアログの破棄について

[戻る]
よし 2008/09/10(水) 11:48:04
環境: WINXP, VC6.0, ダイアログベース

○モードレスダイアログの破棄方法についてご教授下さい。
仕様として下記なのですが、2.3.はクリアしたのですが、
1.をうまく制御できません。

1.子ダイアログは、あるイベントにて何度でも生成可能
2.子ダイアログから親ダイアログへ遷移(子ダイアログは消去)
3.親ダイアログを閉じると子ダイアログも消去

下記に必要そうな部分のコードを抽出しました。
すいませんが、宜しくお願いします。

親ダイアログ(モーダル)
CParentDlgクラス
(.h)
class CParentDlg : public CDialog
{
private
    CChildDlg* m_pdlg;
};
(.cpp)
BOOL CParentDlg::OnCommand(WPARAM wParam, LPARAM lParam) 
{
    switch(wParam) {
    case 1:
    if(m_pdlg) {
        m_pdlg->DestroyWindow();
            delete m_pdlg; <-ここの処理でwarnningが発生
         }
         m_pdlg = new CChildDlg;
    m_pdlg->Create(this);
    m_pdlg->CenterWindow();
    m_pdlg->ShowWindow(SW_SHOW);
    break;
    }
}

子ダイアログ(モードレス)
CChildDlgクラス
(.h)
class CDaily1MinDlg : public CDialog
{
private
    BOOL m_bFlg; // TRUE:メモリ確保中, FALSE:メモリ破棄済み
};
(.cpp)
BOOL CChildDlg::DestroyWindow() 
{
    --- 略(解放処理) ---
    return TRUE;
//  return CDialog::DestroyWindow();
}

void CDaily1MinDlg::PostNcDestroy() 
{
    // ダイアログのデータを削除
    if(m_bFlg) {
      DestroyWindow();
        m_bFlg = FALSE;
  ]
    delete this;
//  CDialog::PostNcDestroy();
}

void CDaily1MinDlg::OnCancel() 
{
    if(m_bFlg) {
        DestroyWindow();
        m_bFlg = FALSE;
    }
    ShowWindow(SW_HIDE);    
//  CDialog::OnCancel();
}

よし 2008/09/10(水) 11:52:12
CDaily1MinDlgクラス → CChildDlgクラスとして読み取って下さい。

Kerry 2008/09/10(水) 12:12:00
> m_bFlg

↑このフラグが何を表しているのかよくわかりません。

1.〜3.の動作を行いたいだけならば以下のようなコードで実現可能です。

class CParentDlg : public CDialog
{
private:
    CChildDlg m_dlg;
};

void CParentDlg::OnXXXX()
{
    if (::IsWindow(m_dlg.m_hWnd))
        m_dlg.DestroyWindow();

    m_dlg.Create(this);
    m_dlg.CenterWindow();
    m_dlg.ShowWindow(SW_SHOW);
}

class CChildDlg : public CDialog
{
};

void CChildDlg::OnCancel()
{
    DestroyWindow();
}

rin 2008/09/10(水) 12:40:38
BOOL CChildDlg::DestroyWindow() 
{
    --- 略(解放処理) ---
    return TRUE;
//  return CDialog::DestroyWindow();
}

ここで基本クラスのDestroyWindowの呼び出しを制限してますが
「    --- 略(解放処理) ---」のところで、
それに変わる内容をちゃんとしてるのでしょうか?

よし 2008/09/10(水) 12:49:57
返答ありがとうございます。

Kerryさん、m_bFlgはDestroyWindow();を処理したか否かのフラグです。

rinさん、DestroyWindow()内のデフォルト処理は残しておいても良いのでしょうか?
// TODO: この位置に固有の処理を追加するか、または基本クラスを呼び出してください
となっていますが。。。

とりあえず、Kerryさんの方法で実装してみます。

よし 2008/09/10(水) 13:37:04
Kerryさんのコードで試してみましたが、子ダイアログのDestroyWindow()内で解放処理
を行い、親ダイアログから子ダイアログのDestroyWindow()処理する為、解放領域を再度
解放しようとする為、落ちてしまいます。
CDialog::DestroyWindow();を実行するとCDialog::PostNcDestroy()を処理してくれるの
でしょうか?

Kerry 2008/09/10(水) 14:02:12
DestroyWindowではなく、子ダイアログのOnDestroy(WM_DESTROY)で
その解放処理とやらを行えばよいと思います。

よし 2008/09/10(水) 14:50:06
下記のように変更したら解決しました。

@子ダイアログにOnDestroy()を追加
ADestroyWindow()では、CDialog::DestroyWindow();を処理
BOnDestroy()では、子ダイアログで確保した領域の解放処理
CPostNcDestroy()では、delete this; を処理

※メモリリーク、ワーニング共に解消されました。
※DestroyWindow() → OnDestroy() → PostNcDestroy() の順で処理してくれるの
 ですね。
※親側で明示的にdeleteしなくてもいいこともわかりました。

返答をくれた方々、ありがとうございます。

よし 2008/09/10(水) 14:50:42
[[解決]]
解決にチェックを入れ忘れたので。。。

たいちう 2008/09/10(水) 16:28:13
いまさらだけど、一時的に非表示にするだけでは駄目だったのかな?

古いスレッドには追加発言できません。