現在、
ダイアログベースのアプリで、
モードレスダイアログから直接モードレスダイアログを呼び、
更にモーダルダイアログを呼んでいます。
つまり、
Dialog-A → Dialog-B → Dialog-C
※
Dialog-A:モードレス
Dialog-B:モードレス(Dialog-Aから直接呼ばれる)
Dialog-C:モーダル(Dialog-Bから直接呼ばれる)
の様になっています。
ここで、Dialog-Cまで表示した状態で、
Dialog-Aにフォーカスを移し、
アプリケーションを終了すると
Debug Assertion Failed!
になってしまいます。
Dialog-Aの終了処理で上手く
Dialog-Cが終了できていないために起っているのでしょうか?
どなたか、教えていただけませんでしょうか。
よろしくお願いします。
これだけではなんとも。
想像で書き込んでも外しそうですから具体的には書きませんが、
せっかく、「Debug Assertion Failed!」が出ているのに全く利用できていないのが気に
なります。
ASSERTが起こった場所まで出ていると思うので、
そこからもう少し具体的に何処でどのタイミングで起こっているのかを
御自分で確認される事をお勧めします。
推測で話を進めてもあまり意味がないと思いますので。
モードレスの実装方法にしても色々ありますからその辺も絡んでいるかもしれません。
PATIOさん。
早速返信いただきましてありがとうございます.
自分なりに調べたことを書かせていただきます.
ちなみに、ソフトウェア全体の構造は
Dialog-0が大本にあり、
このDialog-0から
モードレスダイアログDialog-Aを呼び.
このDialog-AがDialog-Bを呼ぶ~
というようになっております.
つまり、
Dialog-0 → Dialog-A → Dialog-B → Dialog-C
となり、Dialog-Cのみモーダルです。
(それぞれ、次のDialogを直接呼んでいます.)
問題の終了時の動きですが、
Dialog-Aの終了処理で、
Dialog-BをGetSafeHwnd()でチェックし、
必要に応じてDialog-BのDestroyWindow()を呼んでいます.
Dialog-BのDestroyWindow終了後、
Dialog-Aを閉じています.
ASSERTが発生するのは、
Dialog-Aなどを閉じた後に、
Dialog-Bクラス内に記述してあるDialog-CのDoModal関数が終了し、
その次の行に記述してある、
Dialog-BがDialog-Cクラスの関数から値を受け取る処理が走ったときに
発生しているようです.
処理としては、Dialog-Aの終了処理で
Dialog-CのOnCancel処理を実行し、
その後、Dialog-BをGetSafeHwnd()でチェックし、
Dialog-BのDestroyWindow()にて閉じるのが、
順当な処理化と思うのですが、どうでしょうか?
以上、長くなってしまいましたがよろしくお願いします.
補足します.
Dialog-Bのメンバ関数として
Dialog-C.PostMessage(WM_COMMAND, IDCANCEL);
を行う関数clsDlg()を追加し、
Dialog-AにボタンAを追加し、
このボタンAからDialog-B.clsDlg()
を行った後に
Dialog-Aの終了処理を行うとうまくいきます.
しかし、このclsDlg()を
Dialog-Aの終了処理の直前もしくは、終了処理の先頭で
呼んでもASSERTが表示されます.
たぶん、Dialog-Aの終了処理の直前もしくは、終了処理の先頭では
Dialog-Cのメッセージループの処理が行われず、
Dialog-Aの終了処理後にDialog-Cのメッセージループの処理が行われ、
Dialog-Bクラス内に書かれたDialog-C.DoModal()の後の処理を実行
するのではないかと思われます.
(見当違いだったらすいません。)
多分、書かれている話でほぼあっているのだと思います。
モーダルダイアログを終了するだけであれば、
Dialog-C.EndDialog(IDCANCEL);
でも良いかなとは思いますが、
EndDialogは、これを呼んだらすぐにダイアログが終了するようになっていないはずです。
EndDialogはモーダルループに対して終了を指示するんですが、
これは、メッセージハンドラ関数から抜けてメッセージループが動作しないと
駄目だったと思います。
ですから、Dialog-Bは、Dialog-CのDoModal処理が終了して、
DoModalを呼んでいるメッセージハンドラが終了するまで待たなくてはなりません。
この辺は、何か仕掛けを施さないと難しいでしょう。
私なら、Dialog-Cを出す時にDialog-AやDialog-0に対して無効化をかけて
ユーザーのコントロールを不能にし、Dialog-Cが終わる時に有効化して
オペレーション可能にすると思います。
そうすれば、いきなり上位のウインドウから消される事もありませんからね。
その方が仕組み的にもずっと楽です。
Dialog-Cが出ている時にDialog-AやDialog-0を操作できなければならないと言う
理由があれば、難しくてもチャレンジするしかないですね。
PATIOさん、ありがとうございます.
もう少し教えていただきたいのですが、
やはり、
Dialog-C表示中にDialog-AやDialog-0を操作したいです。
仕掛けとして何か有効なものご存知でしょうか?
ちなみに、
Dialog-Bクラス内からDialog-0やDialog-A
(つまり、呼び出しもとのダイアログ)
の無効化はどの様に行うのでしょうか?
長くなってすいませんが、よろしくお願いします.
補足です.
Dialog-AからDialog-Bを作る際に
Createの第二引数をNULLに設定していて、
親子関係になっていませんでした.
Dialog-Aに対して無効化を試すために、
hWnd = GetParentOwner();
hWnd->EnableWindow(FALSE);
のようにしようと思ったのですが、
EnumWindowsで探さなくてはならない状態です。
探すときに、ダイアログIDで探す方法はありますか?
(ダイアログベースのアプリではクラス名での検索ができないようです.)
(また、ダイアログのキャプションではちょっと不安なので。)
よい方法あれば、ぜひ教えていただけますでしょうか.
NULLにしていたのが問題なら、それを適切なウィンドウハンドルを
渡すのが順当だと思いますが。
で、Dialog-AからDialog-Cを閉じる際のアイデアとしては、
・タイマーを使ってDialog-CのハンドルをIsWindow()でチェックするとか、
・フラグを使って、Dialog-Aで自分自身にPostMessage(WM_CLOSE)を送り、
Dialog-CをEndDialog()してWM_CLOSEを殺す。次に来た時にWM_CLOSEを処理する、
とか。
それより、Dialog-Bにメッセージを送って、Dialog-BにDialog-Cの後始末を任せる方が
順当のような気がしますが。
ユーノシステムズのホームページへようこそ!
<ここはどんなサイト?>
プログラミングの話を掲載しています(初心者向け)。
自作フリーソフトの情報も掲載しています。
パソコン関連のご相談に掲示板とメールでお答えします。
運営開始日=2003年9月16日
最終更新日=2004年12月17日
更新履歴
--------------------------------------------------------------------------------
メニュー
プログラミングの話 「プログラミングってなに?」
できるだけかみくだいて説明します。
プログラミングって意外と(?)楽しいよ!
ショートカットキーの話 「ウィンドウズの操作は常にマウスで」
という方、時にはキーボードを活用して
スマートに操作してみませんか?
2進数の話 「2進数? そもそも『~進数』って?」
本格的にプログラミングやるなら必須。
そうでなくても頭の体操にどうぞ!
自作フリーソフト情報 私が製作したフリーソフトを紹介します。
製作エピソードも掲載しています。
パソコンQ&A みなさんからのご相談にお答えします。
掲示板とメールで受け付けています。
掲示板ではみなさんからの回答も
お待ちしています!
ユーノシステムズって? 私のプロフィールです。
雑記 本当は「日記」にしたかったけど、
毎日更新する自信がないのですよ。
リンク集 おすすめのサイトを登録していきます。
みなさんからの自薦も募集中!
ご意見、ご感想等は こちら までメールをお送りください。
お待ちしています!
※都合により返信できないことがあるかもしれません。ご了承ください。
--------------------------------------------------------------------------------
(C)2003 Yuno
RAPTさん、ありがとうございました.
何とか解決しそうです.
PATIO さん、RAPTさん、
本当にありがとうございました.