1

ユーザーがアプリケーションを閉じようとした場合、Close Query 確認ダイアログを表示したいと思います。システムがシャットダウンしたり、タスクまたはプロセスがタスク マネージャーから終了されている場合は、クリーンアップして終了したいだけです。

私はこのコードを試しました:

private
procedure WMEndSession(var Message: TWMEndSession); message WM_ENDSESSION;

...

procedure TxxxForm.WMEndSession(var Message: TWMEndSession);
begin
  gShuttingDown := Message.EndSession;
end;

...

procedure TxxxForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
  Application.ProcessMessages;
  if gShuttingDown then
    CanClose := True
  else
    CanClose := MessageDlg('Are you sure you want to stop the close?', mtConfirmation,
       [mbYes, mbNO], 0) = mrYes;
end;

ポップアップ確認には、プログラムを閉じるか、タスク マネージャーからプロセスを終了するかが表示されます。

4

1 に答える 1

6

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 つの状況に対応する必要があります。

  1. アプリケーション内のカスタム メニューまたはボタンから閉じます。
  2. 標準の Windows コマンドから閉じる:X右上の Sys メニュー、または左上隅をダブルクリック、Alt+F4キーの組み合わせ。
  3. そして最後にタスクマネージャーから閉じます。

3 つすべてを思いどおりに動作させるのは少し難しいです。

  • オプション 3 は、WM_CLOSE. したがって、プロンプトなしで「デフォルト」の動作を閉じる必要があります。a を使用しFlagて、プロンプトを有効にします。このようにして、オプション 3 は「静かに」閉じることができます。
  • オプション 2 は、最初に を送信WM_SYSCOMMANDし、SC_CLOSEその後にWM_CLOSE. Flagしたがって、最初のメッセージに応答して設定できます。したがって、ユーザーはプロンプトを受け取ります。
  • オプション 1 は、ほとんどの場合、 を呼び出すことによって実装されCloseます。ただし、プロンプトを確実に取得するには、最初に設定する必要がありますFlag
  • ユーザーがアプリケーションを閉じないことを選択した場合は、忘れずにクリアしてください。Flag

最終的な考え

個人的には「きっちり確認」がかなり面倒くさいです。もちろん、私は頻繁に保存する習慣があるので、データを失う危険はありません。

基本的に、終了時にプロンプ​​トを表示する唯一の正当な理由は、保存されていないデータの偶発的なデータ損失を防ぐことです。また、次のルールに従えば、より快適なユーザー エクスペリエンスを作成できます。

アプリが開いたら、常に閉じたときとまったく同じ状態に復元してください。

つまり、ドキュメントに保存されていないデータがあった場合は、一時ファイルに保存します。アプリを再度開くと、ドキュメントはシャットダウン時と同じ「編集」状態に自動的に置かれます。

(はい。おそらくこれは単純化しすぎているかもしれませんが、このアイデアはモバイル デバイスで非常にうまく機能します。 )

于 2015-03-06T17:40:23.617 に答える