モードレスダイアログの削除タイミング – プログラミング – Home

モードレスダイアログの削除タイミング
 
通知
すべてクリア

モードレスダイアログの削除タイミング


TAKA
 TAKA
(@TAKA)
ゲスト
結合: 23年前
投稿: 117
Topic starter  

ダイアログ上でモードレスダイアログをCreateし表示しています。
このモードレスダイアログは、どのイベントで削除したらよいのでしょうか?

現在、OnInitDialog()でCreateし、OnDestroy()でDestroyしているのですが、
モードレスダイアログの親ウィンドウをthisにすると、削除時にエラーとなって
しまいます。
<エラー>
ハンドルされていない例外が発生しました : 0xC0000005:

<.h>----------------------------
class CMyDialog : public CDialog
{
protected:
CModelessDialog* m_pDialog;
・・・・・・
}

<.cpp>--------------------------
BOOL CMyDialog::OnInitDialog()
{
m_pDialog = new CModelessDialog;
m_pDialog->Create( CModelessDialog::IDD, this); //thisを削除すればOK
}
void CMyDialog::OnDestroy()
{
CDialog::OnDestroy();
m_pDialog->DestroyWindow();
}

ご教授お願いします。

VC.NET WinXP


引用解決済
トピックタグ
ひろぴー
 ひろぴー
(@ひろぴー)
ゲスト
結合: 22年前
投稿: 182
 

> void CMyDialog::OnDestroy()
> {
> CDialog::OnDestroy();
> m_pDialog->DestroyWindow();
> }
void CMyDialog::OnDestroy()
{
m_pDialog->DestroyWindow();
CDialog::OnDestroy();
}
コレでダメでしょうか?


返信引用
TAKA
 TAKA
(@TAKA)
ゲスト
結合: 23年前
投稿: 117
Topic starter  

ありがとうございます。

> void CMyDialog::OnDestroy()
> {
> m_pDialog->DestroyWindow();
> CDialog::OnDestroy();
> }
> コレでダメでしょうか?

だめでした。


返信引用
ひろぴー
 ひろぴー
(@ひろぴー)
ゲスト
結合: 22年前
投稿: 182
 

> だめでした。
だめでしたか....。
ちなみにVC++6、Win2000ではOKでした。
OnDestroy()に来る前にドコかでDestroyWindowしているなんて事はないでしょうか?


返信引用
dairygoods
 dairygoods
(@dairygoods)
ゲスト
結合: 23年前
投稿: 1421
 

親ウィンドウを指定して作ったウィンドウは、
親ウィンドウが削除された時に一緒に削除されるので、
DestroyWindow() を呼び出す必要はないと思います。


返信引用
TAKA
 TAKA
(@TAKA)
ゲスト
結合: 23年前
投稿: 117
Topic starter  

> 親ウィンドウを指定して作ったウィンドウは、
> 親ウィンドウが削除された時に一緒に削除されるので、
> DestroyWindow() を呼び出す必要はないと思います。

え!そうなんですか?
知りませんでした。

確かに
DestroyWindow()を呼び出さなくとも、モードレスダイアログの
PostNcDestroy()が呼び出されdelete thisできていました。

ありがとうございます。

-------

追加で質問なのですが、
親ウィンドウをNULLにした場合も、
DestroyWindow()は呼び出さなくてもいいのでしょうか?

<.h>----------------------------
class CMyDialog : public CDialog
{
protected:
CModelessDialog* m_pDialog;
・・・・・・
}
<.cpp>--------------------------
BOOL CMyDialog::OnInitDialog()
{
m_pDialog = new CModelessDialog;
m_pDialog->Create( CModelessDialog::IDD, NULL);
}

この場合は、
CMyDialogがm_pDialoを所有しているため、CMyDialogが削除されるとき、
m_pDialog->DestroyWindow();
を呼ばないとだめなのでしょうか?


返信引用
dairygoods
 dairygoods
(@dairygoods)
ゲスト
結合: 23年前
投稿: 1421
 

親ウィンドウを持たないウィンドウの場合は、
どこかのタイミングで明示的にDestroyWindow()を
呼び出さないと正常に削除処理が動きません。

しかし、MFCの場合、親ウィンドウを指定せずにダイアログを作ると
メインウィンドウ(AfxGetMainWnd())が親に指定されるため、
メインウィンドウが削除される時に一緒に削除されます。
#CDialog::Create()の中をデバッガで追っかけてみてください。

ちなみに、メンバ変数による所有関係と
ウィンドウの親子関係は関係ありません。


返信引用
TAKA
 TAKA
(@TAKA)
ゲスト
結合: 23年前
投稿: 117
Topic starter  

当方少し勘違いしている部分がありもう一度整理します。

モードレスダイアログの表示から削除までの流れ
1.CMyViewでCMyDialogをDoModa()する。
2.CModelessDialog* m_pDialog(インスタンスのポインタ)はCMyDialogが所有
3.CModelessDialogはCMyDialog::OnInitDialog()で作成表示
4.CMyDialogのクローズとともにCModelessDialogを削除する

<MyDialog.h>----------------------------
class CMyDialog : public CDialog
{
protected:
CModelessDialog* m_pDialog;
・・・・・・
}

<MyDialog.cpp>--------------------------
BOOL CMyDialog::OnInitDialog()
{
m_pDialog = new CModelessDialog;
m_pDialog->Create( CModelessDialog::IDD, this); // <-----(1)
}
void CMyDialog::OnDestroy()
{
CDialog::OnDestroy();
m_pDialog->DestroyWindow(); // <----(2)
}

<CModelessDialog.cpp>--------------------------
void CModelessDialog::PostNcDestroy()
{
CDialog::PostNcDestroy();
delete this;
// <----(3)
}

当初のエラーの原因は(1)で親ウィンドウをthisにした場合、
CMyDialogのクローズの処理で、(3)が呼ばれた後(1)が実行されるため
エラーになっていました。

なお、(1)で親ウィンドウをNULLにした場合は、
CMyDialogのクローズの処理で、(3)が呼ばれずに(1)が実行されるため
正常処理となります。

そこでCModelessDialogは親ウィンドウが削除されると同時に
(3)が呼び出される削除されるということで、
(2)のm_pDialog->DestroyWindow()は呼び出す必要がなくなりました。

以上より、(2)のm_pDialog->DestroyWindow()を削除しました。

そこで問題なのですが、
親ウィンドウをNULLした場合、メインウィンドウが親ウィンドウとなるため、
CMyView内でCMyDialogをDoModal()すると、DoModal()の回数だけ
CModelessDialogがCreateしてしまいます。
また、メインウィンドウがCloseするとき、CModelessDialog::PostNcDestroy()がCreate
回数分
実行されるため、動作的には正常です。しかし、メインウィンドウがCloseするまでは、
削除されない
ということになってしまいます。

親ウィンドウをNULLした場合、CModelessDialogのCreateが一回ですむような方法はない
のでしょうか?

一般にモードレスダイアログの作成、削除はどのようにするものなのでしょうか?


返信引用
dairygoods
 dairygoods
(@dairygoods)
ゲスト
結合: 23年前
投稿: 1421
 

どうも、CModelessDialogをどのように使いたいのかがはっきりしないのですが、

・CModelessDialogはCMyDialogが表示されるときに一緒に表示される。
・CMyDialogを閉じると一緒に消える。
・再度CMyDialogを開くと、またCModelessDialogが表示されるが、
 これは新しく作られたCModelessDialogではなく、
 前回のものが再表示されて欲しい。

ということですか?


返信引用
TAKA
 TAKA
(@TAKA)
ゲスト
結合: 23年前
投稿: 117
Topic starter  

> ・CModelessDialogはCMyDialogが表示されるときに一緒に表示される。
> ・CMyDialogを閉じると一緒に消える。
> ・再度CMyDialogを開くと、またCModelessDialogが表示されるが、
>  これは新しく作られたCModelessDialogではなく、
>  前回のものが再表示されて欲しい。

前回のCModelessDialogが再表示でもいいのですが、
前回のCModelessDialogが削除された後、新たにCModelessDialogが作られるという感じ
です。
また、前回のCModelessDialogの削除は、CMyDialogを閉じるタイミングとあわせて削除
されるという動作がベターです。


返信引用
dairygoods
 dairygoods
(@dairygoods)
ゲスト
結合: 23年前
投稿: 1421
 

> 前回のCModelessDialogが再表示でもいいのですが、
> 前回のCModelessDialogが削除された後、新たにCModelessDialogが作られるという感じ
> です。

それでしたら、CModelessDialogの親をCMyDialogにしておけば
よいと思うのですが。


返信引用
ゆう
 ゆう
(@ゆう)
ゲスト
結合: 23年前
投稿: 114
 

気になることがあるのですが、
TAKA さんのコードで CModelessDialog の親を NULL にして実行すると、
メモリリークを起こしそうな気がしますが、気のせいでしょうか。。。

CMyDialog のオブジェクトが CMyView のメンバの場合は、delete されていない
m_pDialog を new するのでマズイと思いますし、
ある関数内で宣言されているのでしたら delete されないないまま
オブジェクトが破棄されてしまいますのでメモリリークを起こすと思うのですが。

>void CModelessDialog::PostNcDestroy()
>{
> CDialog::PostNcDestroy();
> delete this; // <--- ここを削除して
>}
としないで

void CMyDialog::OnDestroy()
{
CDialog::OnDestroy();
m_pDialog->DestroyWindow();
delete m_pDialog; // <--- このようにする
}

とした方が安全ではないでしょうか?
ちなみに、私の方法で実行したところ 親を this にしても NULL にしても
エラーは発生しませんでしたよ。


返信引用
TAKA
 TAKA
(@TAKA)
ゲスト
結合: 23年前
投稿: 117
Topic starter  

> void CMyDialog::OnDestroy()
> {
> CDialog::OnDestroy();
> m_pDialog->DestroyWindow();
> delete m_pDialog; // <--- このようにする
> }

ゆうさんの言うとおりですね。

モードレスダイアログは、必ずPostNcDestroy() で
delete this するものだと勘違いしていました。

この方法の場合
親をthisにした時、CModelessDialogのOnDestroyが
2回呼ばれまずいのではと思ったのですが、
なぜか1回しか呼ばれませんでした。

ありがとうございます。


返信引用

返信する

投稿者名

投稿者メールアドレス

タイトル *

プレビュー 0リビジョン 保存しました
共有:
タイトルとURLをコピーしました