2

Control-C、Control-Break、ログオフ、ウィンドウ X ボタンの押下などで機能するものを一緒に考え出すことはできますか?

これが私がこれまでに持っているものです:

class Program
{  
    private static ConsoleEventHandlerDelegate consoleHandler;
    delegate bool ConsoleEventHandlerDelegate(CtrlTypes eventCode);

    static void Main(string[] args)
    {
        consoleHandler = new ConsoleEventHandlerDelegate(ConsoleCtrlCheck);
        SetConsoleCtrlHandler(consoleHandler, true);

        System.Diagnostics.Process.GetCurrentProcess().Exited 
           += delegate(object sender, EventArgs e) 
        {              
            GeneralManager.Stop();
        };

        Console.CancelKeyPress += delegate(object sender,
                                ConsoleCancelEventArgs e)
        {
            e.Cancel = false;
            GeneralManager.Stop();
        };

        GeneralManager.Start();
    }

    private static bool ConsoleCtrlCheck(CtrlTypes ctrlType)
    {
        switch (ctrlType)
        {                
            case CtrlTypes.CTRL_C_EVENT:

                Console.WriteLine("CTRL+C received!");
                GeneralManager.Stop();
                break;

            case CtrlTypes.CTRL_BREAK_EVENT:
                isclosing = true;
                Console.WriteLine("CTRL+BREAK received!");
                GeneralManager.Stop();
                break;

            case CtrlTypes.CTRL_CLOSE_EVENT:

                Console.WriteLine("Program being closed!");
                GeneralManager.Stop();
                break;

            case CtrlTypes.CTRL_LOGOFF_EVENT:
            case CtrlTypes.CTRL_SHUTDOWN_EVENT:

                Console.WriteLine("User is logging off!");
                GeneralManager.Stop();
                break;                           
        }
        return true;
    }

    #region unmanaged

            [DllImport("kernel32.dll")]
          static extern bool SetConsoleCtrlHandler(ConsoleEventHandlerDelegate
            handlerProc, bool add);

    public delegate bool HandlerRoutine(CtrlTypes CtrlType);

    public enum CtrlTypes
    {
        CTRL_C_EVENT = 0,
        CTRL_BREAK_EVENT,
        CTRL_CLOSE_EVENT,
        CTRL_LOGOFF_EVENT = 5,
        CTRL_SHUTDOWN_EVENT
    }

    #endregion
}

2 つの問題:

  1. Managed Control-Break ハンドラーで設定e.Cancel = trueすると、.Net4 の例外で失敗します。これは、回避策のない MSDN の記事に記載されています: http://msdn.microsoft.com/en-us/library/system.consolecanceleventargs.cancel.aspx

  2. でクローズをキャンセルする方法がわかりませんConsoleCtrlCheck。クリーンアップを行うのに 1 ~ 2 秒かかりますが、キャンセルして、すべてが適切に行われることを確認したいと思います。

アップデート:

返信ありがとうございます。両方に賛成しました。私が求めたことを直接解決する回答を誰かが思い付くことができるかどうかを確認するのを待ちます。それ以外の場合は、「NT サービスを使用する」回答のいずれかを受け入れます。

4

3 に答える 3

3

保留中のユーザー要求が完了するのを待ち、それらを完全に切断し、データベースでいくつかのクエリを実行して、状態の変更を反映する必要があります。TCPサーバーです。

次に、コンソールまたはその他の種類のクライアント アプリとして実行しないでください。

それを Windows (NT) サービスとして実行するだけで、心配する必要があるイベントは電力損失と停止信号だけです。

UPS を使用して、適切な期間内に閉鎖できることを確認してください。

于 2012-09-22T11:57:46.443 に答える
1

この種のことをコンソール アプリで実行しようとしたことはありませんが、Windows フォーム (または WCF アプリ) を使用するとうまくいく可能性があります。彼らはあなたにFormClosingキャンセル可能なイベントを提供します。または、ネットワーク サービスを作成している場合は、Windows サービスを使用します。これは、アプリケーションを完全に停止するためのインターフェイスを提供します。

コンソール アプリに本当に熱心な場合は、おそらくtry {} finally {}すべてのコードを囲む句や、クリティカル ファイナライザーなどのより風変わりなものによって、クリーンアップ コードを実行できる場合があります。しかし、これは実際にはこの仕事に適したツールではありません。

また、電源障害やタスク マネージャーの kill コマンドなど、アプリが閉じられるのを防ぐことができない場合があります (アプリが X 経由で閉じられなかった場合、タスク マネージャーは私が最初に使用するツールです)。

そのため、すべてのクライアント要求がトランザクション ログに記録されるようにサービス アプリケーションをコーディングします (SQL サーバーが行うように)。予期せず中断された場合 (状況が何であれ)、その時点までに発生したことはすべてログに記録されます。サービスが次に開始されるときに、そのログを再生します。

ログに記録する内容の 1 つは、「私は完全にシャットダウンされましたT」です。再起動してもログの最後にその項目が見つからない場合は、何か問題が発生したことがわかり、必要なアクションを実行できます。

サービスが何をしているかを知る必要がある場合は、多くのロギング フレームワークの 1 つを使用して、アクティビティを表示するだけの 2 番目のアプリにイベントをパイプします。

于 2012-09-22T11:54:43.197 に答える
0

私はこれを見て数時間を費やしましたが、今は動作するコードを構築する時間がありません。おそらく短いですが、それを正しくするのにはしばらく時間がかかります。これを行うために必要なさまざまなものへのリンクを提供します。

http://pastebin.com/EzX3ezrf

貼り付けのコードからの教訓を要約すると、次のようになります。

  1. WM_QUERYENDSESSION、WM_ENDSESSION、CTRL_SHUTDOWN_EVENT の一部/すべてを処理するメッセージ ポンプが必要です (c# では SystemEvents.SessionEnding がこれらの一部/すべてをカバーする場合があります)。

  2. メッセージ ポンプを取得する最も簡単な方法は、非表示のフォーム/ウィンドウ アプリにすることですが、コンソール アプリとしてビルドしてメッセージ ポンプを追加することも可能であることを思い出します。ただし、そのコードはペーストに含めませんでした。

  3. 「アプリケーションが潜在的なシステム シャットダウンをブロックする必要がある場合は、ShutdownBlockReasonCreate 関数を呼び出すことができます」

  4. AllocConsole を使用してコンソールを作成するため、SetConsoleCtrlHandler を使用し、ハンドラーで ExitThread(1) を使用する必要があります。これは、そうでなければコンソールを閉じるスレッドを殺す「ハック」です。FarManager で使用されます。たとえば、interf.cpp を参照してください

  5. AllocConsole を使用する場合は、コンソールの初期化とクリーンアップも必要です。

  6. CTRL+C を押すと、入力がおかしくなることが報告されています。FarManager がこのシナリオを処理しているかどうかはわかりません。interf.cpp の CTRL_BREAK_EVENT ハンドラーに、何をするかわからないコードがいくつかあります。

  7. FarManager は WM_POWERBROADCAST も処理します。おそらくサスペンドに関係しています。

それだけでは不十分な場合 (あるべきです)、コンソールを別のプロセスに追加して、ここに示すようにメッセージを IPC することもできます。AllocConsole で開始されたコンソールを閉じると、アプリケーション全体が終了するのはなぜですか? この動作を変更できますか?

RMTool を使用して、テスト用のログオフ/シャットダウン メッセージをシミュレートできます

MSDN には、microsoft.win32.systemevents.sessionending.aspx および microsoft.win32.systemevents.aspx (隠しフォームの例) にもいくつかの C# コードがあります。

mischel.com/pubs/consoledotnet/consoledotnet.zip には、AllocConsole が使用され、いくつかのイベントが処理されたサンプルの winTest プロジェクトがあります。

于 2014-02-01T22:33:30.397 に答える