開発環境:VS2008、MFC
Win7でのみ、どんな状態でもタスクバーからウィンドウを閉じる事が
出来るようなのですが、これを無効化する方法はないでしょうか?
あるボタンを押すと「はい」「いいえ」のメッセージボックスを出し、
その戻り値によって動きを変えるプログラムなのですが、
メッセージボックスを出してる最中でもタスクバーから終了できてしまいます。
※WinXPやWinVistaではタスクバーからいつでも終了できる機能はないようです。
特別な不具合に繋がっているわけではありませんが、
出来れば無効化させたいです。
Win7にお詳しい方、よろしくお願いします。
MFCを使わずに試してみましたが,
「ウィンドウを閉じる」では普通にWM_CLOSEが送られてくるだけでした。
なので,WM_CLOSEのハンドラでメッセージボックスを出しているか調べ,
出していたらDefWindowProcを呼ばないようにすればよいのではないでしょうか。
なお,MessageBox APIをオーナーウィンドウを指定して呼び出した場合,
「ウィンドウを閉じる」でWM_CLOSEは送られてきませんでした。
オーナーウィンドウにNULLを指定していた場合は,
「ウィンドウを閉じる」でWM_CLOSEが送られてきます。
情報ありがとうございます。
メッセージボックスを出している場合かどうかを調べる場合はどうすれば良いのでしょ
うか?
メッセージボックスのハンドルが取れればよいのですが、取り方がわかりません。
MessageBox APIはオーナーウィンドウを指定して呼び出しています。
その場合は、「ウィンドウを閉じる」を実行すると即座に終了するわけではないのです
が、
「はい」「いいえ」を選択してメッセージを閉じると終了してしまいます。
メッセージを閉じた後に、WM_CLOSEが飛んでいるのでしょうか?
なお、メッセージ表示中は親画面を操作させたくないので、NULLは指定したくありませ
ん。
> メッセージボックスを出している場合かどうかを調べる場合はどうすれば良いのでしょ
うか?
メッセージボックスを出しているのは,あなたのプログラムですよね。
なので,プログラム側で「出していること」のフラグを用意して,
メッセージボックスを出す前後で上げ下げすれば,OnCloseで確認できます。
ただ,手元で試した限り,オーナーウィンドウを設定さえしておけば,
メッセージボックス表示中に閉じるような事態にはなりませんでしたが。
> 「はい」「いいえ」を選択してメッセージを閉じると終了してしまいます。
閉じたくない場合はCFrameWnd::OnCloseを呼ばない,ということをしていますか。
呼ばなければ,閉じることはないです。
確認
1:アプリケーションを立ち上げる
2:ユーザーに「はい/いいえ」を問うメッセージボックスを呼び出す(終了とは無関係
の内容)
3:2状態のときに、タスクバー>右メニュー>ウィンドウを閉じる を選択
4:3をしてもこの時点ではすぐには何もおきない
5:2で立ち上げたメッセージボックスを終了させる
6:アプリケーションが終了してしまう(3が今頃効いてきた?)
こんな流れでしょうか?
>YuOさん
フラグで管理するのは考えたのですが、小手先の回避のような気がして
メッセージボックス
>ryoさん
はい、その手順どおりで合っています。
わかりにくかったかもしれませんので、
ryoさんの例にもうちょっと補足します。
【プログラム】
画面Aから「はい/いいえ」のメッセージを表示し、
はい →画面B
いいえ→画面C
を表示するプログラムとします
(画面Aは消えないまま残ります)
1:アプリを立ち上げる(画面A)
2:ボタンを押して、「はい/いいえ」を問うメッセージボックスを呼び出す
3:2を表示中に、タスクバー>右メニュー>ウィンドウを閉じる を選択
4:3をしてもこの時点ではすぐには何もおきない
5:「はい」または「いいえ」を選択
6:画面Aが閉じてしまうが、画面Bが開かれる
(3が実行されたが、5の選択結果も実行された)
このように、中途半端に終了処理が走ってしまい困っています。
何とかこのタスクバーからの終了を回避させたいです。
YuOさんのおっしゃるように、フラグで管理するしかないんでしょうか?
> YuOさんのおっしゃるように、フラグで管理するしかないんでしょうか?
YuOさんが調べたとおり、「WM_CLOSE」が送られてきましたか?
問題のメッセージボックスを実行しないようにすると確実OnClose()にとんできますか?
とんでくるとすると、それはWINDOWSの仕様になると思います。
OnClose()内の処理で対応するしかないと思います。
WINDOWSの処理として、「WM_CLOSE」などのウインドウメッセージより、実際の
プログラムの処理が優先されます。
今回の場合、「WM_CLOSE」のウインドウメッセージよりメッセージボックスの処理
が優先されたのだと思います。
ただ、システムからの、「WM_CLOSE」を無視していると何かしら問題がでる可能性が
あります。
「強制終了です。」等のメッセージボックスを表示して無視せずに終了した方がいい
のかも知れません。
やり取りを見ていて気になったんですが、
掲示板でのやり取りに関しては誰も保障してくれないので
実際に掲示板に書き込まれている内容が自分の所で起こっている現象と
一致するのかを必ず確認してから話を進めるようにしたほうが良いです。
書き込みをしている方もいろいろ実験して下さったりしていると思いますが、
あくまでも好意でやっている訳で情報の正確さを保障しているわけではありません。
書き込まれた情報が間違っていたり、勘違いしているケースもありえますし。
で、不具合の解消には状況の把握が不可欠です。
何が原因でそういう現象が起こっているのかまで突き詰めないと
不具合の解消は出来ません。
結果的に意図した動作をするようになったとしても
それは状況を悪くしているだけかもしれません。
統合開発環境を使っているならデバッガという便利な道具があるわけですから
まずは起こっている現象を出来る限り正確に掴める様に努力しましょう。
デバッガの使い方わからないなら、使い方の勉強をすればよいだけです。
(実際の話、勉強するだけの価値はあると思います)
追記
アプリケーションの振る舞いだけに着目して内部の処理を想像するのは
取っ掛かりとしては正しいと思いますが、それだけで状況を判断するには
情報として精度が足りないと思います。
デバッガで追うなり、TRACEで出力させてみるなりして
実際に起こっている処理の内容を追いかけないと真因に迫ることは出来ないと思います
よ。
>箱さんへ
状況はだいだいわかりましたが・・・
私の知る限り、異常な動作だと思います
たとえば、
1.メモ帳を開く
2.メニュー>ヘルプ>バージョン情報 でダイアログ出す
3.タスクバー>…を行う
4.バージョン情報ダイアログを閉じる
これをやってもメモ帳は終了しません。
また、
新規にダイアログベースからメッセージボックスを出すプロジェクトつくって
それで、実験してみたけれどやはり起きません。
ですので、起きてる現状をフラグなどで回避するよりは
まず起きないように修正すべきだと思います。
で、これについてのアドヴァイスなのですが
私の手元では再現できないので…ごめんなさい
画面Aがどこでどうやって終了してるのか
デバッグモードで1ステップずつ追いかけてみたり
今回の現象には直接影響しないであろう部分をコメントアウトして、
発生するかどうかみたり
もしくは、新しいプロジェクトをつくり、
最小限の内容で、現象が再現できるものがつくれるのかどうか?
など、調査してみるしかないと思います。
試してみました。
タスクバーからウィンドウを閉じるを実行すると、
オーナーウィンドウにWM_SYSCOMMAND(SC_CLOSE)が発行されます。
OnSysCommandで何かしていますか。
# 箱さんの動作とはちがいますが、
# VS2003だとCPropertySheet::OnSysCommandは、
# Modelessの場合PostMessage(WM_CLOSE)を呼んでいました。不吉な感じがします。
ところで、ウィンドウを閉じるでオーナーウィンドウは
無効にもかかわらずアクティブになりました。
Windows7の新しい仕様だと思います。
みなさん、アドバイスありがとうございます。
ここに書き込める環境では、開発環境が無く
思い出しつつ書いてるため間違いがあればすみません。
そこで、上で私が挙げているかなりはしょって書いた【例】のプログラムですが、
試しに作ってみたら再現しませんでした。すみません。
そこで、元となっているプログラムから内容を削って試してみたところ
以下の状態で発生することがわかりました。
【作ったプログラム】
・システムメニュー付きのダイアログベースで作成
・InitInstanceでPropertySheetを作成し、PropertyPageを追加
・PropertyPageにはボタンを追加
・ボタン押下で「はい/いいえ」のメッセージボックス表示
※メッセージボックスにはPropertyPageのウィンドウハンドルを指定
・終了時(OnQueryCancel、OnClose)に確認メッセージを表示
【手順】
1:アプリ起動
2:ボタンを押して、「はい/いいえ」を問うメッセージボックスを呼び出す
3:2を表示中に、タスクバー>右メニュー>ウィンドウを閉じる を選択
このように行うと、「はい/いいえ」のメッセージ表示中にも関わらず
OnQueryCancel()で設定した確認メッセージが「はい/いいえ」の上に
表示されてしまいます。(二重にメッセージが表示される)
OnCloseのメッセージは表示されないので、通ってないと思います。
(※開発環境がVistaで、実行環境がWin7なので
デバッガ環境がないので、確認できません、すみません)
なお、普通のダイアログにボタンを設置して
同じ手順を踏んでも二重にメッセージが表示されることはありませんでした。
(OnCloseも通っていないようです)
私が現在作っている元のプログラムもPropertySheetを使っているので、
ロマさんの補足でもありますが、これが原因ではないかと思っています。
日付と時刻の設定プロパティシートは、箱さんと同様の動作でした。
ということで、Windows7の仕様だろうと思いますので、
タスクバーからの終了は生かしたほうが良いのかも知れません。
ただし、WM_SYSCOMMAND(SC_CLOSE)はPSN_RESETを呼び、
WM_SYSCOMMANDの終了後にMessageBoxの後の処理が続きますので、
PSN_RESETでリソースを解放していると、対策が必要かも。
その他、
Windows7でファイル名を指定して実行ダイアログは、
参照ボタンからファイル参照ダイアログを出していると、
タスクバーからの終了はできなくなります。
UIが統一されていない感じです。
調べて頂いて、ありがとうございます。
プロパティシートで作った際にいつでもタスクバーからの終了が効いてしまう、
(SC_CLOSEが飛んでくる)というのはWindows7のバグのようなものなのでしょうか。
普通のダイアログで作成した場合は起きないようなので、
仕様というのも変な気がします。
私が作成しているプログラムでは、
プロパティシートの様々な箇所からメッセージボックスを出すようにしています。
すべての箇所で、メッセージ表示中は終了を無効にしたいと考えているため
メッセージを表示する前にフラグON、表示が終わればフラグOFF、
のようにやっているとかなりの量になってしまいます。
※フラグが立っていたらSC_CLOSEを無効にします
何とか一元化できないかな、と思っていますが、
タスクバーからの終了が無効化できないとなると何か良い方法ないのでしょうか?
うーん。
> すべての箇所で、メッセージ表示中は終了を無効にしたいと考えているため
> メッセージを表示する前にフラグON、表示が終わればフラグOFF、
> のようにやっているとかなりの量になってしまいます。
> ※フラグが立っていたらSC_CLOSEを無効にします
フラグのON/OFFとメッセージ表示をセットにした関数を作成して
それを呼び出すようにするくらいですかねぇ。
いずれにしてもメッセージ表示の部分は置換えざるえないと思いますけれど。