.NET控制台应用程序退出事件
在.NET中,是否有方法(如事件)来检测控制台应用程序何时退出? 我需要清理一些线程和COM对象。
我正在从控制台应用程序运行一个消息循环,没有窗体。 我正在使用的DCOM组件似乎要求应用程序泵送消息。
我已经尝试添加一个处理程序Process.GetCurrentProcess.Exited和Process.GetCurrentProcess.Disposed。
我也尝试添加一个处理程序到Application.ApplicationExit和Application.ThreadExit事件,但他们不是射击。 也许这是因为我没有使用表单。
您可以使用AppDomain
的ProcessExit
事件:
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"); } }
更新
下面是一个完整的示例程序,在单独的线程上运行一个空的“消息泵”,允许用户在控制台中input退出命令以优雅地closures应用程序。 在MessagePump中循环之后,你可能会想要以一种很好的方式清理线程所使用的资源。 出于以下原因,最好在ProcessExit中执行此操作:
- 避免交叉线程问题; 如果在MessagePump线程上创build了外部COM对象,那么在那里处理它们会更容易。
- 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"); } }
该应用程序是一个简单的运行,直到系统closures或收到一个Ctrl + C或控制台窗口closures的服务器。
由于申请的特殊性质,“优雅地”退出是不可行的。 (这可能是我可以编写另一个应用程序,它会发送一个“服务器closures”的消息,但这将是一个应用程序矫枉过正,仍然不足以满足某些情况下,如服务器(实际操作系统)实际上是closures时。
由于这些情况,我添加了一个“ 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#代码的相同的东西的链接。
这是一个完整的,非常简单的.Net解决scheme,适用于所有版本的Windows。 只需粘贴到一个新的项目,运行它,并尝试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.."); } } }
对于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); }
如果您正在使用控制台应用程序,并且正在泵送消息,是不是可以使用WM_QUIT消息?