【转】捕获控制台程序关闭事件-SetConsoleCtrlHandler
原文地址:https://blog.csdn.net/yanggenxiang/article/details/7692957
有时候运行在服务器上的控制台程序,需要记录详细的运行日志,这就需要对程序关闭进行日志记录,以便能根据日志了解程序的运行状况。比如正在运行的程序被人不小心关闭了,导致最终任务没有运行成功,这时日志也没有错误记录,对分析原因造成不便,记录了关闭事件日志后就能了解到这种情况是程序被终止了。这样注意通过消息钩子来实现,通过调用WIN32 API SetConsoleCtrlHandler方法来实现,具体代码如下:
using System; using System.Diagnostics; using System.Runtime.InteropServices; namespace TestClose { public delegate bool ConsoleCtrlDelegate(int ctrlType); class Program { [DllImport("kernel32.dll")] private static extern bool SetConsoleCtrlHandler(ConsoleCtrlDelegate HandlerRoutine, bool Add); //当用户关闭Console时,系统会发送次消息 private const int CTRL_CLOSE_EVENT = 2; //Ctrl+C,系统会发送次消息 private const int CTRL_C_EVENT = 0; //Ctrl+break,系统会发送次消息 private const int CTRL_BREAK_EVENT = 1; //用户退出(注销),系统会发送次消息 private const int CTRL_LOGOFF_EVENT = 5; //系统关闭,系统会发送次消息 private const int CTRL_SHUTDOWN_EVENT = 6; static void Main(string[] args) { Console.WriteLine("开始:"); Program cls = new Program(); Console.Read(); } public Program() { ConsoleCtrlDelegate consoleDelegete = new ConsoleCtrlDelegate(HandlerRoutine); bool bRet = SetConsoleCtrlHandler(consoleDelegete, true); if (bRet == false) //安装事件处理失败 { Debug.WriteLine("error"); } else { Console.WriteLine("ok"); Console.Read(); } } private static bool HandlerRoutine(int ctrlType) { switch (ctrlType) { case CTRL_C_EVENT: //Console.WriteLine("C"); break; case CTRL_BREAK_EVENT: //Console.WriteLine("BREAK"); break; case CTRL_CLOSE_EVENT: //Console.WriteLine("CLOSE"); break; case CTRL_LOGOFF_EVENT: break; case CTRL_SHUTDOWN_EVENT: break; } //return true;//表示阻止响应系统对该程序的操作 return false;//忽略处理,让系统进行默认操作 } } }
实战
public Program() { #region --监控关闭按钮-- public delegate bool ControlCtrlDelegate(int ctrlType); [DllImport("kernel32.dll")] private static extern bool SetConsoleCtrlHandler(ControlCtrlDelegate handlerRoutine, bool add); private static readonly ControlCtrlDelegate CancelHandler = HandlerRoutine; /// <summary> /// //设置关闭监控时间 /// SetConsoleCtrlHandler(CancelHandler, true); /// </summary> /// <param name="ctrlType"></param> /// <returns></returns> public static bool HandlerRoutine(int ctrlType) { switch (ctrlType) { case 0: //Ctrl+C关闭 case 2: //按控制台关闭按钮关闭 //关闭处理 break; } return false; } #endregion }