WM_QUERYENDSESSIONは、処理する正しいメッセージです。これは前に送信されWM_ENDSESSION
、次の VCL コードに従って、WMQueryEndSession がすぐに を呼び出すことがわかりますCloseQuery
。
procedure TCustomForm.WMQueryEndSession(var Message: TWMQueryEndSession);
begin
Message.Result := Integer(CloseQuery);
end;
上記の実装は、VCL コードの小さなバグであると考えることができます。これは、WM_QUERYENDSESSION
ドキュメントに記載されているように (強調は私のもの):
各アプリケーションは、このメッセージを受信するとすぐに TRUE または FALSE を返し、WM_ENDSESSION メッセージを受信するまでクリーンアップ操作を延期する必要があります。
アプリケーションは、シャットダウン時にユーザーに情報を求めるユーザー インターフェイスを表示できますが、推奨されません。5 秒後、システムはシャットダウンを妨げているアプリケーションに関する情報を表示し、ユーザーがそれらを終了できるようにします。たとえば、Windows XP ではダイアログ ボックスが表示されますが、Windows Vista ではシャットダウンをブロックしているアプリケーションに関する追加情報が全画面表示されます。アプリケーションがシステムのシャットダウンをブロックまたは延期する必要がある場合は、ShutdownBlockReasonCreate
関数を使用します。詳細については、「Windows Vista のシャットダウンの変更」を参照してください。
たまたまポップアップしたダイアログに 5 秒以内に応答しない場合、ユーザーはアプリを終了するか、シャットダウンをキャンセルする必要があります。残念ながら、CloseQuery
通常はユーザーにプロンプトを表示するために使用されるので、そうするのは得策ではありません。
注: これは、Vista より前のバージョンでは完全に許容されていました。上記のコードは、おそらく従来の問題です。CloseQuery
ただし、少なくとも終了要求のソースを示すように調整して、Query End Session の特定のケースに簡単に対処できるようにするとよいでしょう。
したがって、WM_QUERYENDSESSION に応答してプロンプトをポップアップさせたくないので、実際には次のようにします。
procedure TxxxForm.WMQueryEndSession(var Message: TWMQueryEndSession);
begin
Message.Result := 1;
{ Do not call inherited bc VCL may prevent/delay shutdown via
calls to: CloseQuery and CallTerminateProcs (in older
versions of Delphi).
As per Vista requirements, this should not be done. Use
ShutdownBlockReasonCreate and ShutdownBlockReasonDestroy to
control when shutdown is allowed. }
end;
質問の 2 番目の部分に進みます。
上記がEnd Taskタスク マネージャー経由で機能しない理由は、タスク マネージャーがシャットダウンと同じメカニズムを使用しないためです。WM_CLOSE
アプリケーションにメッセージを送信するだけです。
したがって、アプリケーションが「通常」に閉じられたときとまったく同じように動作することはまったく問題ありません。実際、メモ帳でこれを試すことができます。
- メモ帳を開く
- テキストを入力します
- タスク マネージャーに移動し、[End Taskメモ帳] をクリックします。
- メモ帳が確認を求めるプロンプトを表示し、タスク マネージャーに、メモ帳がユーザーからの応答を待っていることを示すダイアログが表示されます。(少なくとも Win7 では。)
ただし、タスク マネージャーを閉じるときにプロンプトを表示しないようにしたい、または防止する必要がある場合は、そうすることができます。ただし、コードは多くの特殊なケースに対処する必要があり、すべてのバージョンの Windows でまったく同じように動作するとは限りません。(そのため、本当に努力する価値があるかどうかを自問する必要があります。)
少なくとも 3 つの状況に対応する必要があります。
- アプリケーション内のカスタム メニューまたはボタンから閉じます。
- 標準の Windows コマンドから閉じる:X右上の Sys メニュー、または左上隅をダブルクリック、Alt+F4キーの組み合わせ。
- そして最後にタスクマネージャーから閉じます。
3 つすべてを思いどおりに動作させるのは少し難しいです。
- オプション 3 は、
WM_CLOSE
. したがって、プロンプトなしで「デフォルト」の動作を閉じる必要があります。a を使用しFlag
て、プロンプトを有効にします。このようにして、オプション 3 は「静かに」閉じることができます。
- オプション 2 は、最初に を送信
WM_SYSCOMMAND
し、SC_CLOSE
その後にWM_CLOSE
. Flag
したがって、最初のメッセージに応答して設定できます。したがって、ユーザーはプロンプトを受け取ります。
- オプション 1 は、ほとんどの場合、 を呼び出すことによって実装され
Close
ます。ただし、プロンプトを確実に取得するには、最初に設定する必要がありますFlag
。
- ユーザーがアプリケーションを閉じないことを選択した場合は、忘れずにクリアしてください。
Flag
最終的な考え
個人的には「きっちり確認」がかなり面倒くさいです。もちろん、私は頻繁に保存する習慣があるので、データを失う危険はありません。
基本的に、終了時にプロンプトを表示する唯一の正当な理由は、保存されていないデータの偶発的なデータ損失を防ぐことです。また、次のルールに従えば、より快適なユーザー エクスペリエンスを作成できます。
アプリが開いたら、常に閉じたときとまったく同じ状態に復元してください。
つまり、ドキュメントに保存されていないデータがあった場合は、一時ファイルに保存します。アプリを再度開くと、ドキュメントはシャットダウン時と同じ「編集」状態に自動的に置かれます。
(はい。おそらくこれは単純化しすぎているかもしれませんが、このアイデアはモバイル デバイスで非常にうまく機能します。 )