.NET控制台应用程序退出事件.NET控制台应用程序退出事件(.NET Console Applic

2019-06-12 07:17发布

在.NET中,有一个方法,诸如事件,用于当控制台应用程序正在退出检测? 我需要清理一些线程和COM对象。

我运行一个消息循环,没有一种形式,从控制台应用程序。 我使用一个DCOM组件似乎需要应用程序泵消息。

我曾尝试添加一个处理程序Process.GetCurrentProcess.Exited和Process.GetCurrentProcess.Disposed。

我也尝试添加一个处理程序Application.ApplicationExit和Application.ThreadExit事件,但他们不点火。 也许这是因为我没有使用的形式。

Answer 1:

您可以使用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有以下几个原因有:

  • 避免交叉线程问题; 如果MessagePump线程上创建外部COM对象,它更容易有对付他们。
  • 有上ProcessExit时间限制(3秒默认情况下),所以如果清理耗时,如果该事件处理程序中pefromed它可能会失败。

下面是代码:

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");
    }
}


Answer 2:

这是在所有版本的Windows工作的完成,非常简单的.NET解决方案。 只需将其粘贴到一个新的项目,运行它,并尝试CTRL-C来查看它如何处理它:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;

namespace TestTrapCtrlC{
    public class Program{
        static bool exitSystem = false;

        #region Trap application termination
        [DllImport("Kernel32")]
        private static extern bool SetConsoleCtrlHandler(EventHandler handler, bool add);

        private delegate bool EventHandler(CtrlType sig);
        static EventHandler _handler;

        enum CtrlType {
         CTRL_C_EVENT = 0,
         CTRL_BREAK_EVENT = 1,
         CTRL_CLOSE_EVENT = 2,
         CTRL_LOGOFF_EVENT = 5,
         CTRL_SHUTDOWN_EVENT = 6
         }

        private static bool Handler(CtrlType sig) {
            Console.WriteLine("Exiting system due to external CTRL-C, or process kill, or shutdown");

            //do your cleanup here
            Thread.Sleep(5000); //simulate some cleanup delay

            Console.WriteLine("Cleanup complete");

            //allow main to run off
             exitSystem = true;

            //shutdown right away so there are no lingering threads
            Environment.Exit(-1);

            return true;
        }
        #endregion

        static void Main(string[] args) {
            // Some biolerplate to react to close window event, CTRL-C, kill, etc
            _handler += new EventHandler(Handler);
            SetConsoleCtrlHandler(_handler, true);

            //start your multi threaded program here
            Program p = new Program();
            p.Start();

            //hold the console so it doesn’t run off the end
            while(!exitSystem) {
                Thread.Sleep(500);
            }
        }

        public void Start() {
            // start a thread and start doing some processing
            Console.WriteLine("Thread started, processing..");
        }
    }
 }


Answer 3:

该应用程序是简单地运行,直到系统关闭或者它接收到Ctrl + C或控制台窗口被关闭的服务器。

由于应用的特殊性,它不是“正常”退出可行的。 (这可能是因为我可以编写另一个应用程序这将发出一个“服务器关闭”消息,但是这将是矫枉过正了一个应用程序,仍不足以某些情况下,当服务器(实际OS)实际上是关闭等。)

因为这些情况下,我增加了一个“ ConsoleCtrlHandler ”在那里我停下我的线程和清理我的COM对象等等......


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#代码同样的事情。



Answer 4:

对于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);
}


Answer 5:

如果您使用的是控制台应用程序,你都抽的消息,你不能使用WM_QUIT消息?



Answer 6:

作为一个很好的例子可能是值得的, 浏览到这个项目 ,看看如何处理退出过程语法或从此片段VM在这里找到

                ConsoleOutputStream = new ObservableCollection<string>();

                var startInfo = new ProcessStartInfo(FilePath)
                {
                    WorkingDirectory = RootFolderPath,
                    Arguments = StartingArguments,
                    RedirectStandardOutput = true,
                    UseShellExecute = false,
                    CreateNoWindow = true
                };
                ConsoleProcess = new Process {StartInfo = startInfo};

                ConsoleProcess.EnableRaisingEvents = true;

                ConsoleProcess.OutputDataReceived += (sender, args) =>
                {
                    App.Current.Dispatcher.Invoke((System.Action) delegate
                    {
                        ConsoleOutputStream.Insert(0, args.Data);
                        //ConsoleOutputStream.Add(args.Data);
                    });
                };
                ConsoleProcess.Exited += (sender, args) =>
                {
                    InProgress = false;
                };

                ConsoleProcess.Start();
                ConsoleProcess.BeginOutputReadLine();
        }
    }

    private void RegisterProcessWatcher()
    {
        startWatch = new ManagementEventWatcher(
            new WqlEventQuery($"SELECT * FROM Win32_ProcessStartTrace where ProcessName = '{FileName}'"));
        startWatch.EventArrived += new EventArrivedEventHandler(startProcessWatch_EventArrived);

        stopWatch = new ManagementEventWatcher(
            new WqlEventQuery($"SELECT * FROM Win32_ProcessStopTrace where ProcessName = '{FileName}'"));
        stopWatch.EventArrived += new EventArrivedEventHandler(stopProcessWatch_EventArrived);
    }

    private void stopProcessWatch_EventArrived(object sender, EventArrivedEventArgs e)
    {
        InProgress = false;
    }

    private void startProcessWatch_EventArrived(object sender, EventArrivedEventArgs e)
    {
        InProgress = true;
    }


文章来源: .NET Console Application Exit Event