截获控制台程序关闭事件(SetConsoleCtrlHandler)
最近控制台程序中需要捕获控制台关闭事件,在用户关闭的时候进行某些操作,找了一大圈发现了一个方法,通过调用WIN32 API SetConsoleCtrlHandler方法来实现,具体代码如下:
1 using System; 2 using System.Windows.Forms; 3 using System.Diagnostics; 4 using System.Runtime.InteropServices; 5 6 namespace ConsoleColsed 7 { 8 public delegate bool ConsoleCtrlDelegate(int ctrlType); 9 class Program 10 { 11 [DllImport("kernel32.dll")] 12 private static extern bool SetConsoleCtrlHandler(ConsoleCtrlDelegate HandlerRoutine, bool Add); 13 //当用户关闭Console时,系统会发送次消息 14 private const int CTRL_CLOSE_EVENT = 2; 15 //Ctrl+C,系统会发送次消息 16 private const int CTRL_C_EVENT = 0; 17 //Ctrl+break,系统会发送次消息 18 private const int CTRL_BREAK_EVENT = 1; 19 //用户退出(注销),系统会发送次消息 20 private const int CTRL_LOGOFF_EVENT = 5; 21 //系统关闭,系统会发送次消息 22 private const int CTRL_SHUTDOWN_EVENT = 6; 23 24 static void Main(string[] args) 25 { 26 Program cls = new Program(); 27 28 } 29 public Program() 30 { 31 ConsoleCtrlDelegate consoleDelegete = new ConsoleCtrlDelegate(HandlerRoutine); 32 33 bool bRet = SetConsoleCtrlHandler(consoleDelegete, true); 34 if (bRet == false) //安装事件处理失败 35 { 36 Debug.WriteLine("error"); 37 } 38 else 39 { 40 Console.WriteLine("ok"); 41 Console.Read(); 42 } 43 } 44 45 private static bool HandlerRoutine(int ctrlType) 46 { 47 switch(ctrlType) 48 { 49 case CTRL_C_EVENT:// Ctrl+C 事件 50 Console.WriteLine("-- CTRL_C_EVENT --"); 51 break; 52 case CTRL_BREAK_EVENT: 53 Console.WriteLine("-- CTRL_BREAK_EVENT --"); 54 break; 55 case CTRL_CLOSE_EVENT://用户点 X 关闭事件 56 Console.WriteLine("-- CTRL_CLOSE_EVENT --"); 57 break; 58 case CTRL_LOGOFF_EVENT: 59 break; 60 case CTRL_SHUTDOWN_EVENT://系统关闭事件 61 break; 62 } 63 //return true;//表示阻止响应系统对该程序的操作 64 return false;//忽略处理,让系统进行默认操作 65 } 66 } 67 }
不过这个方法我在运用的时候遇到了这样的一个问题:对“::Invoke”类型的已垃圾回收委托进行了回调。这可能会导致应用程序崩溃、损坏和数据丢失。即使将项目 属性-》生成-》忽略不安全代码 这个选项打勾,仍然出现这个错误,除非用Release模式编译运行。Debug模式或者直接运行EXE文件都会报错,在网上查找了一圈找到一个解决方法,那就是先声明一个回调委托的成员变量,这样可以防止被垃圾回收。