- ベストアンサー
OnDestroy() について
- CInputクラスのOnDestroy()が呼び出されない問題について
- 新しく追加したダイアログバーによりOnDestroy()が呼び出されるようになった理由について
- みんなの回答 (7)
- 専門家の回答
質問者が選んだベストアンサー
><疑問1> >このような方法は強引でスマートでない気がするのですが、 >付箋ソフトにてアプリ終了時に付箋紙の状態を記録する処理を >ダイアログの破棄時に行おうとしていることが仕様と >しておかしいのでしょうか? いいんじゃないんですか? それで。 ウィンドウが親子になっていないのでいたら、個別に消すのはあたりまえということで。 スマートさにこだわるのであれば、メインウィンドウはずっと透明で、付箋は全部子ウィンドウにしておくって位ですかねぇ。 >このような場合はダイアログが破棄されておらず、スレッド? >が残っていると聞いたことがあるのですが、そうなのですか? スレッドは残りません。 Win32になって、原則としてプロセスの終了時にはプロセスが使用していた資源はOSが解放しているはずだからです。 #OSのバグで資源が残る場合も・・・ ただし、あんまり行儀がいいとはいえないので、終了時には資源を正しく開放してあげるのがいいと思いますよ。 >これにも反して、OnCancelが呼ばれずに破棄されていると言うことで問題ありと言うことなのでしょうか? そういうことになりますかねぇ。 >あと、OKボタンを押した場合の処理はどうすれば良いのか? >とかいろいろな疑問が沸いてきて、モードレスダイアログを使った正しいアプリの終了方法とはどうやるのでしょう? OnCancelをオーバーライドしなければいけない理由は、CDialog::OnCancelの中でEndDialogが呼ばれることでダイアログが非表示になってしまうからです。 おそらく、CDialog::OnOkの中でもEndDialogを呼んでいるので、OKボタンがダイアログにあるのでしたらCDialog::OnOkは呼び出さずにDestroyWindowで破棄ということになるでしょう。
その他の回答 (6)
- taka_tetsu
- ベストアンサー率65% (1020/1553)
>しかしながら、やりたいことはメインウィンドウを閉じたときにダイアログのOnDestroyを実行することです。 一旦Windowsアプリの基本に戻りましょう。 SDKでウィンドウアプリを作成するときのメッセージループって知ってますか? while (GetMessage(&msg,NULL,0,0)) { TranslateMessage(&msg); DispatchMessage(&msg); } こんなやつですよね。 このwhileループでキューにたまったメッセージを各ウィンドウのプロシージャに送っています。 このループの終了条件は、GetMessageがFALSEを返すとき、すなわちWM_QUITを受け取ったときです。 ではWM_QUITが送られるのは?というとPostQuitMessageが呼ばれたときです。 では、PostQuitMessageを呼び出すのはいつ? ということですと、メインウィンドウがWM_DETROYを受け取ったときということです。 では、WM_DESTROYが送られるのは?というと、DestroyWindowが呼ばれたときです。 ここらへんはSDKでウィンドを作ったことがあれば理解できると思います。 で、本題に戻りますが、 WM_DESTROYが親ウィンドウに送られた場合、子ウィンドウにもWM_DESTROYが送られます。つまり、逆に考えると、親子関係がないウィンドウにはWM_DESTROYが送られないということになります。 つまり、あとから作成したモードレスダイアログにはWM_DESTROYが送られないまま、メインウィンドウはWM_QUITを受け取ってメッセージループを抜けてアプリが終了しています。アプリが終了してしまうともちろんモードレスダイアログは存在不可能なので、消えます。 ということで、OnDestroyが呼ばれない現象が発生します。 では、モードレスダイアログとの関係が親子になっていないときにVitaminBBさんのプログラムで追加が必要なことは何かというと、モードレスダイアログを破棄するという処理が必要になります。 つまり、メインウィンドウのOnDestroyで、全てのモードレスウィンドウのDestroyWindowを呼び出して、ダイアログの終了処理をさせる必要があるということです。 WM_DESTROYは、親子以外には勝手には送られてこないということですね。
お礼
いつも回答ありがとうございます。 大変良く分かります。 >メインウィンドウのOnDestroyで、全てのモードレスウィンドウのDestroyWindowを呼び出して、ダイアログの終了処理をさせる必要があるということです。 ということで、やってみました。 もちろんうまく行きました。 <疑問1> このような方法は強引でスマートでない気がするのですが、付箋ソフトにてアプリ終了時に付箋紙の状態を記録する処理をダイアログの破棄時に行おうとしていることが仕様としておかしいのでしょうか? 慣れてしまえばなんでもない気もしますが。 <疑問2> >つまり、あとから作成したモードレスダイアログにはWM_DESTROYが送られないまま、メインウィンドウはWM_QUITを受け取ってメッセージループを抜けてアプリが終了しています。アプリが終了してしまうともちろんモードレスダイアログは存在不可能なので、消えます。 このような場合はダイアログが破棄されておらず、スレッド?が残っていると聞いたことがあるのですが、そうなのですか? >>OnCancelを必ずオーバーライドしてDestroyWindowを自分で呼び出してください。 これにも反して、OnCancelが呼ばれずに破棄されていると言うことで問題ありと言うことなのでしょうか? あと、OKボタンを押した場合の処理はどうすれば良いのか? とかいろいろな疑問が沸いてきて、モードレスダイアログを使った正しいアプリの終了方法とはどうやるのでしょう? #済みません。だんだん話が込み入ってきました。 疑問2は面倒だったらほかっておいてください。
- taka_tetsu
- ベストアンサー率65% (1020/1553)
>>OnCancelを必ずオーバーライドしてDestroyWindowを自分で呼び出してください。 > >これって、Cancelボタンを使う場合は、自分でオーバーライドして使いましょうということだと思うのですが、私が知りたいのは、 いえ、違います。 urlの内容、ちゃんと読みました? >モードレス ダイアログ ボックスをインプリメントするときは、 >必ず OnCancel メンバ関数をオーバーライドし、その中から >DestroyWindow を呼び出します。基本クラスの > CDialog::OnCancel を呼び出さないでください。 という記述です。 モードレスダイアログを作成するときは、必ずOnCancelをオーバーライドしてくださいということです。 ちなみに、OnCancelは、キャンセルボタンを押されたときだけではなく、ESCを押されたり、右上の×ボタンを押されたときにも呼ばれるハンドラです。 この中で、フレームワークがEndDialogを呼んでしまっているので、ダイアログが破棄されたように見えても実際は非表示になっているだけということです。 >アプリ終了時にモードレスダイアログのOnDestroy()を実行させるにはどうすれば良いのでしょうか? なので、自分でOnCancelをオーバーライドして、DestroyWindowで破棄をすることでOnDestroyが呼ばれます。 OnDestroyが呼ばれるのはWM_DESTROYが送られてきたときです。 これが送られるのはDestroyWindowをコールしたときのみです。 EndDialogしか呼ばれていなかったらWM_DESTROYは送られてこないので、OnDestroyが呼ばれない、 ということです。
お礼
回答ありがとうございます。 言われていることは理解できました。 確かにダイアログの×ボタンで閉じるとOnDestroyが実行されるようになりました。 しかしながら、やりたいことはメインウィンドウを閉じたときにダイアログのOnDestroyを実行することです。 どうすれば出来るようになりますか? (もともとやろうとしてることが変なのかな?)
- taka_tetsu
- ベストアンサー率65% (1020/1553)
#こっちを忘れてました。 >アプリ終了時に付箋紙のメモデータや位置データを保存するには、いつどのクラスで実行するのが良いのでしょうか? 普通に考えると、保存は付箋紙のウィンドウを破棄する前でしょうね。そうしないと位置情報取れませんし。 #もちろんOnMoveとかで常に位置情報を退避してたら別ですけど、そんなこと普通しませんよね。 保存先のクラスに関しては、いろいろと考え方やメリットデメリットががありますのであくまで例です。 まず、各ウィンドウのクラス中で保存すると、他のウィンドウを意識することなくデータの管理ができるのでこの点では楽です。 ただ、アプリ全体のデータはどうしてもCWinAppで管理することになるので、うまく作らないとデータの構造がぐしゃぐしゃになる恐れがあります。 CWinAppの中ですべてのウィンドウの情報を保存するとなると、リスト等でそれぞれのウィンドウの情報を区別するような仕組みを作る必要が出てきます。しかし、データは1箇所にまとめられるので管理が楽になります。 自分で作るとしてもどっちにするかぱっとは決められませんね。
お礼
回答ありがとうございます。 結局、最近質問していることは全てこの仕様をどうするかに関わっています。 付箋紙のウィンドウでデータを管理するよりこれらをまとめて面倒をみる人に任せたほうが良いと考えました。 メインウィンドウは非表示にしているので(ボタン等を配置できないため、なんとなく面倒を見る人として使わないほうが良いと思い)、その人を付箋ウィンドウの親であるデータ入力ダイアログにしました。 その結果、アプリが終了したことをダイアログが知ることが出来ない状況に陥ってしまい。色々悩んでいます。 (但し、ダイアログをメインウィンドウの子供にしてやれば問題無くうまく行っています。)
- taka_tetsu
- ベストアンサー率65% (1020/1553)
>ダイアログを閉じた時もアプリ終了時にもメッセージが飛んできません。 どうしてなのですか? http://www.microsoft.com/japan/developer/library/vcmfc/_mfc_cdialog.htm だそうです。 OnCancelを必ずオーバーライドしてDestroyWindowを自分で呼び出してください。 ということで。
お礼
いつも回答ありがとうございます。 まだまだレベルが低いので変なこと言ってたら済みません。 >OnCancelを必ずオーバーライドしてDestroyWindowを自分で呼び出してください。 これって、Cancelボタンを使う場合は、自分でオーバーライドして使いましょうということだと思うのですが、私が知りたいのは、 アプリ終了時にモードレスダイアログのOnDestroy()を実行させるにはどうすれば良いのでしょうか? ということなのです。 #この後にした質問で、 1つの方法としてダイアログをメインウィンドウの子供とすれば、メッセージが飛んでくることが分かりましたが、これ以外の方法は無いのでしょうか?
- taka_tetsu
- ベストアンサー率65% (1020/1553)
>#ダイアログバーを追加する勉強をしたプロジェクトをベースにソフトを作成し完成に至りましたが、不要なコードを削除・整理しようと思い、ダイアログバー追加コードを削除したらダイアログをOnDestroy() するときに実行していたコードが動かなくなってしまい困ってます。 VC++が自動生成した個所もどこか手動で削除しましたか? さすがに「どこかを消したら動かなくなった」ではわかりません・・・
お礼
回答ありがとうございます。 余計なことを書いたので話がややこしくなったようで済みません。 別の言い方をすると、 メインウィンドウを非表示にして、 代りにダイアログを入力用として表示し、 ダイアログのボタン押し下げで作成したウィンドウを付箋紙としてデスクトップに貼っている 貼りつけたときに、時付箋紙の情報をダイアログのメンバ変数である配列で保持している このような場合において アプリ終了時に付箋紙のメモデータや位置データを保存するには、いつどのクラスで実行するのが良いのでしょうか?
補足
コードを消した話は無かったことにして、もう一度説明させてください。 一からコードを書き直して、質問1のようにダイアログを作成しただけでは、アプリ終了時にダイアログのOnDestroy() は実行されません。 また、質問2のようにダイアログバーを追加すると、ダイアログのOnDestroy() が実行されるようになります。 どうしてこのような差が出るのでしょうか? また、ダイアログバーの追加などというちょっと変わった方法ではなく、普通ににOnDestroy() が実行されるようにするには、どうすれば良いのでしょうか?
- taka_tetsu
- ベストアンサー率65% (1020/1553)
>AfxMessageBox("789"); ではなく、 MessageBox("789", "789", MB_OK); で試してください。 それとメッセージボックスで確認するだけではなく、 デバッグを。 ><質問2> AfxMessageBox()はメインウィンドウが作成されていないと表示されないことがあります。
お礼
回答ありがとうございます。 <質問1の状態> デバッグしましたが、void CInput::OnDestroy() は実行されません。どうすれば実行されるように出来るのでしょうか? <質問2の状態> 常にメインウィンドウに対し、ダイアログが前面にあります。また、クリックすればウィンドウもダイアログもアクティブになります。 質問1のときは、メインウィンドウをクリックすればメインウィンドウが前面に来ます。 #ダイアログバーを追加する勉強をしたプロジェクトをベースにソフトを作成し完成に至りましたが、不要なコードを削除・整理しようと思い、ダイアログバー追加コードを削除したらダイアログをOnDestroy() するときに実行していたコードが動かなくなってしまい困ってます。
お礼
回答ありがとうございます。 最初はモーダルに対しモードレスダイアログのあまりに特殊なお作法に戸惑いを感じ色々お聞きしましたが、なんとなく分かってきました。 今回の件はここで一旦終わりにし、何かあれば改めて質問させてください。