102

.NET で、コンソール アプリケーションの終了を検出するためのイベントなどの方法はありますか? いくつかのスレッドとCOMオブジェクトをクリーンアップする必要があります。

コンソール アプリケーションからフォームなしでメッセージ ループを実行しています。私が使用している DCOM コンポーネントでは、アプリケーションがメッセージをポンプする必要があるようです

Process.GetCurrentProcess.Exited および Process.GetCurrentProcess.Disposed にハンドラーを追加しようとしました。

また、 Application.ApplicationExitおよびApplication.ThreadExitイベントにハンドラーを追加しようとしましたが、それらは起動しません。おそらくそれは、フォームを使用していないためです。

4

5 に答える 5

98

ProcessExit次のイベントを使用できますAppDomain

class Program
{
    static void Main(string[] args)
    {
        AppDomain.CurrentDomain.ProcessExit += new EventHandler(CurrentDomain_ProcessExit);           
        // do some work

    }

    static void CurrentDomain_ProcessExit(object sender, EventArgs e)
    {
        Console.WriteLine("exit");
    }
}

アップデート

以下は、空の「メッセージ ポンプ」が別のスレッドで実行されている完全なサンプル プログラムです。これにより、ユーザーはコンソールで終了コマンドを入力して、アプリケーションを正常に終了できます。MessagePump のループの後、スレッドが使用するリソースを適切な方法でクリーンアップする必要があるでしょう。いくつかの理由から、ProcessExit よりもそこで行う方が良いです:

  • クロススレッドの問題を回避します。外部 COM オブジェクトが MessagePump スレッドで作成された場合は、そこで処理する方が簡単です。
  • ProcessExit には制限時間 (既定では 3 秒) があるため、クリーンアップに時間がかかる場合、そのイベント ハンドラー内で実行すると失敗する可能性があります。

コードは次のとおりです。

class Program
{
    private static bool _quitRequested = false;
    private static object _syncLock = new object();
    private static AutoResetEvent _waitHandle = new AutoResetEvent(false);

    static void Main(string[] args)
    {
        AppDomain.CurrentDomain.ProcessExit += new EventHandler(CurrentDomain_ProcessExit);
        // start the message pumping thread
        Thread msgThread = new Thread(MessagePump);
        msgThread.Start();
        // read input to detect "quit" command
        string command = string.Empty;
        do
        {
            command = Console.ReadLine();
        } while (!command.Equals("quit", StringComparison.InvariantCultureIgnoreCase));
        // signal that we want to quit
        SetQuitRequested();
        // wait until the message pump says it's done
        _waitHandle.WaitOne();
        // perform any additional cleanup, logging or whatever
    }

    private static void SetQuitRequested()
    {
        lock (_syncLock)
        {
            _quitRequested = true;
        }
    }

    private static void MessagePump()
    {
        do
        {
            // act on messages
        } while (!_quitRequested);
        _waitHandle.Set();
    }

    static void CurrentDomain_ProcessExit(object sender, EventArgs e)
    {
        Console.WriteLine("exit");
    }
}
于 2009-07-13T14:42:50.387 に答える
21

アプリケーションは、システムがシャットダウンするか、Ctrl+を受信するCか、コンソール ウィンドウが閉じられるまで、単純に実行されるサーバーです。

アプリケーションの異常な性質により、「正常に」終了することは現実的ではありません。(「サーバーのシャットダウン」メッセージを送信する別のアプリケーションをコーディングできるかもしれませんが、それは1つのアプリケーションにとってはやり過ぎであり、サーバー(実際にはオペレーティングシステム)が実際にシャットダウンしている場合などの特定の状況では不十分です。)

このような状況のため、スレッドを停止して COM オブジェクトをクリーンアップする「 ConsoleCtrlHandler 」を追加しました...


Public Declare Auto Function SetConsoleCtrlHandler Lib "kernel32.dll" (ByVal Handler As HandlerRoutine, ByVal Add As Boolean) As Boolean

Public Delegate Function HandlerRoutine(ByVal CtrlType As CtrlTypes) As Boolean

Public Enum CtrlTypes
  CTRL_C_EVENT = 0
  CTRL_BREAK_EVENT
  CTRL_CLOSE_EVENT
  CTRL_LOGOFF_EVENT = 5
  CTRL_SHUTDOWN_EVENT
End Enum

Public Function ControlHandler(ByVal ctrlType As CtrlTypes) As Boolean
.
.clean up code here
.
End Function

Public Sub Main()
.
.
.
SetConsoleCtrlHandler(New HandlerRoutine(AddressOf ControlHandler), True)
.
.
End Sub

このセットアップは完璧に機能するようです。これは、同じことの C# コードへのリンクです。

于 2009-07-13T15:09:41.577 に答える
10

CTRL+C の場合、これを使用できます。

// Tell the system console to handle CTRL+C by calling our method that
// gracefully shuts down.
Console.CancelKeyPress += new ConsoleCancelEventHandler(Console_CancelKeyPress);


static void Console_CancelKeyPress(object sender, ConsoleCancelEventArgs e)
{
            Console.WriteLine("Shutting down...");
            // Cleanup here
            System.Threading.Thread.Sleep(750);
}
于 2009-07-13T15:13:41.693 に答える
2

コンソール アプリケーションを使用していて、メッセージをポンピングしている場合は、WM_QUIT メッセージを使用できる場合があります。

于 2009-07-13T14:43:29.713 に答える