ダイアログ上でモードレスダイアログを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
> void CMyDialog::OnDestroy()
> {
> CDialog::OnDestroy();
> m_pDialog->DestroyWindow();
> }
void CMyDialog::OnDestroy()
{
m_pDialog->DestroyWindow();
CDialog::OnDestroy();
}
コレでダメでしょうか?
ありがとうございます。
> void CMyDialog::OnDestroy()
> {
> m_pDialog->DestroyWindow();
> CDialog::OnDestroy();
> }
> コレでダメでしょうか?
だめでした。
> だめでした。
だめでしたか....。
ちなみにVC++6、Win2000ではOKでした。
OnDestroy()に来る前にドコかでDestroyWindowしているなんて事はないでしょうか?
親ウィンドウを指定して作ったウィンドウは、
親ウィンドウが削除された時に一緒に削除されるので、
DestroyWindow() を呼び出す必要はないと思います。
> 親ウィンドウを指定して作ったウィンドウは、
> 親ウィンドウが削除された時に一緒に削除されるので、
> 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();
を呼ばないとだめなのでしょうか?
親ウィンドウを持たないウィンドウの場合は、
どこかのタイミングで明示的にDestroyWindow()を
呼び出さないと正常に削除処理が動きません。
しかし、MFCの場合、親ウィンドウを指定せずにダイアログを作ると
メインウィンドウ(AfxGetMainWnd())が親に指定されるため、
メインウィンドウが削除される時に一緒に削除されます。
#CDialog::Create()の中をデバッガで追っかけてみてください。
ちなみに、メンバ変数による所有関係と
ウィンドウの親子関係は関係ありません。
当方少し勘違いしている部分がありもう一度整理します。
モードレスダイアログの表示から削除までの流れ
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が一回ですむような方法はない
のでしょうか?
一般にモードレスダイアログの作成、削除はどのようにするものなのでしょうか?
どうも、CModelessDialogをどのように使いたいのかがはっきりしないのですが、
・CModelessDialogはCMyDialogが表示されるときに一緒に表示される。
・CMyDialogを閉じると一緒に消える。
・再度CMyDialogを開くと、またCModelessDialogが表示されるが、
これは新しく作られたCModelessDialogではなく、
前回のものが再表示されて欲しい。
ということですか?
> ・CModelessDialogはCMyDialogが表示されるときに一緒に表示される。
> ・CMyDialogを閉じると一緒に消える。
> ・再度CMyDialogを開くと、またCModelessDialogが表示されるが、
> これは新しく作られたCModelessDialogではなく、
> 前回のものが再表示されて欲しい。
前回のCModelessDialogが再表示でもいいのですが、
前回のCModelessDialogが削除された後、新たにCModelessDialogが作られるという感じ
です。
また、前回のCModelessDialogの削除は、CMyDialogを閉じるタイミングとあわせて削除
されるという動作がベターです。
> 前回のCModelessDialogが再表示でもいいのですが、
> 前回のCModelessDialogが削除された後、新たにCModelessDialogが作られるという感じ
> です。
それでしたら、CModelessDialogの親をCMyDialogにしておけば
よいと思うのですが。
気になることがあるのですが、
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 にしても
エラーは発生しませんでしたよ。
> void CMyDialog::OnDestroy()
> {
> CDialog::OnDestroy();
> m_pDialog->DestroyWindow();
> delete m_pDialog; // <--- このようにする
> }
ゆうさんの言うとおりですね。
モードレスダイアログは、必ずPostNcDestroy() で
delete this するものだと勘違いしていました。
この方法の場合
親をthisにした時、CModelessDialogのOnDestroyが
2回呼ばれまずいのではと思ったのですが、
なぜか1回しか呼ばれませんでした。
ありがとうございます。