環境: 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();
}
CDaily1MinDlgクラス → CChildDlgクラスとして読み取って下さい。
> 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();
}
BOOL CChildDlg::DestroyWindow()
{
--- 略(解放処理) ---
return TRUE;
// return CDialog::DestroyWindow();
}
ここで基本クラスのDestroyWindowの呼び出しを制限してますが
「 --- 略(解放処理) ---」のところで、
それに変わる内容をちゃんとしてるのでしょうか?
返答ありがとうございます。
Kerryさん、m_bFlgはDestroyWindow();を処理したか否かのフラグです。
rinさん、DestroyWindow()内のデフォルト処理は残しておいても良いのでしょうか?
// TODO: この位置に固有の処理を追加するか、または基本クラスを呼び出してください
となっていますが。。。
とりあえず、Kerryさんの方法で実装してみます。
Kerryさんのコードで試してみましたが、子ダイアログのDestroyWindow()内で解放処理
を行い、親ダイアログから子ダイアログのDestroyWindow()処理する為、解放領域を再度
解放しようとする為、落ちてしまいます。
CDialog::DestroyWindow();を実行するとCDialog::PostNcDestroy()を処理してくれるの
でしょうか?
DestroyWindowではなく、子ダイアログのOnDestroy(WM_DESTROY)で
その解放処理とやらを行えばよいと思います。
下記のように変更したら解決しました。
①子ダイアログにOnDestroy()を追加
②DestroyWindow()では、CDialog::DestroyWindow();を処理
③OnDestroy()では、子ダイアログで確保した領域の解放処理
④PostNcDestroy()では、delete this; を処理
※メモリリーク、ワーニング共に解消されました。
※DestroyWindow() → OnDestroy() → PostNcDestroy() の順で処理してくれるの
ですね。
※親側で明示的にdeleteしなくてもいいこともわかりました。
返答をくれた方々、ありがとうございます。
解決にチェックを入れ忘れたので。。。
いまさらだけど、一時的に非表示にするだけでは駄目だったのかな?