• 控制‘控制台应用程序’的关闭操作


    控制台程序足够简洁,但是,经常会点错而误关闭。而且,如果系统关闭,或者用户注销,这时候任务还没完成的话,前面的运算电费就白出了。
    有没有办法和WinForm一样,对控制台的退出事件进行控制呢?有的!
    引入下面的函数

    public delegate bool HandlerRoutine(int dwCtrlType);
    
    [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
    public static extern bool SetConsoleCtrlHandler(HandlerRoutine HandlerRoutine, bool add);

    委托HandlerRoutine,就是把函数的指针传递给系统API函数SetConsoleCtrlHandler。这是个典型的回调函数。
    然后在Main方法中调用

    Program p = new Program();
    if (!SetConsoleCtrlHandler(p.HandlerRoutineMethod, true))
    {
        Console.WriteLine("Unable to install event handler!\n");
    }
    const int CTRL_C_EVENT = 0;
        const int CTRL_BREAK_EVENT = 1;
        const int CTRL_CLOSE_EVENT = 2;
        const int CTRL_LOGOFF_EVENT = 5;
        const int CTRL_SHUTDOWN_EVENT = 6;
    
        public bool HandlerRoutineMethod(int dwCtrlType)
        {
            Console.WriteLine(dwCtrlType.ToString());
            switch (dwCtrlType)
            {
                case CTRL_C_EVENT:
                    return true;
                case CTRL_BREAK_EVENT:
                    return false;
                case CTRL_CLOSE_EVENT:
                    Console.WriteLine("确实要退出程序么?如果需要退出,请输入'exit'。");
                    return true;
                case CTRL_LOGOFF_EVENT:
                    //用户退出
                    return false;
                case CTRL_SHUTDOWN_EVENT:
                    //系统关闭
                    return false;
            }
            return true;
        }

    HandlerRoutineMethod函数,就是系统的真实回调。如果返回的结果为false,则程序关闭,否则,不会关闭。
    这里只在CTRL_BREAK_EVENT(按下Ctrl+Break),CTRL_LOGOFF_EVENT用户退出,和系统关闭 CTRL_SHUTDOWN_EVENT,事件时,调用了return false,也就是说,这个时候会关闭。但是在关闭之前我们可以做一些操作。
    试想这样的情况,这个任务可能需要运行很长时间,要能在程序关闭的时候有个保存当前进度的方法,那么就可以采用以上操作了。
    来看个完整的代码

    class Program
    {
        static void Main(string[] args)
        {
            Program p = new Program();
            if (!SetConsoleCtrlHandler(p.HandlerRoutineMethod, true))
            {
                Console.WriteLine("无法注册系统事件!\n");
            }
    
            while (true)
            {
                string s = Console.ReadLine();
                if (s == "exit")
                    GenerateConsoleCtrlEvent(p.CTRL_BREAK_EVENT, 0);
            }
        }
    
        const int CTRL_C_EVENT = 0;
        const int CTRL_BREAK_EVENT = 1;
        const int CTRL_CLOSE_EVENT = 2;
        const int CTRL_LOGOFF_EVENT = 5;
        const int CTRL_SHUTDOWN_EVENT = 6;
    
        public bool HandlerRoutineMethod(int dwCtrlType)
        {
            Console.WriteLine(dwCtrlType.ToString());
            switch (dwCtrlType)
            {
                case CTRL_C_EVENT:
                    return true;
                case CTRL_BREAK_EVENT:
                    Save();
                    return false;
                case CTRL_CLOSE_EVENT:
                    Console.WriteLine("确实要退出程序么?如果需要退出,请输入'exit'。");
                    return true;
                case CTRL_LOGOFF_EVENT:
                    //用户退出
                    Save();
                    return false;
                case CTRL_SHUTDOWN_EVENT:
                    //系统关闭
                    Save();
                    return false;
            }
            return true;
        }
    
        void Save()
        {
            //保存当前进度
        }
    
        public delegate bool HandlerRoutine(int dwCtrlType);
    
        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        public static extern bool SetConsoleCtrlHandler(HandlerRoutine HandlerRoutine, bool add);
    
        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        public static extern bool GenerateConsoleCtrlEvent(int code, int value);
    }

    先 是用SetConsoleCtrlHandler方法,设置了HandlerRoutineMethod为他的回调函数。那么当有事件过来的时候,会先调用这个方法。这个方法return false,则窗体关闭,true,则窗体不关闭。
    GenerateConsoleCtrlEvent方法是通知系统事件的。我们这里假设,只有用户输入exit,或者按Ctrl+Break的时候程序退出。对于用户退出和系统关闭,只是保存当前进度。
    在while 循环中,如果用户输入exit命令,则通知系统调用回调函数HandlerRoutineMethod,调用的事件是Ctrl+Break。
    现在控制台是不是比以前好用了很多呢?:)

    原创文字只代表本人某一时间内的观点或结论,本人不对涉及到的任何代码担保。转载请标明出处!

  • 相关阅读:
    JS中for循环两种写法的坑
    office web apps安装部署,配置https,负载均衡(三)服务器连接域控制器
    office web apps安装部署,配置https,负载均衡(二)域控制器安装并配置域账号
    office web apps安装部署,配置https,负载均衡(一)背景介绍
    如何申请阿里云免费SSL证书(可用于https网站)并下载下来
    树莓派Raspberry实践笔记-常用Linux命令
    树莓派Raspberry实践笔记—轻松解决apt-get慢的问题
    树莓派Raspberry实践笔记-Arduino IDE
    树莓派Raspberry实践笔记—显示分辨率配置
    关于如何坚持自学的3本图书分享
  • 原文地址:https://www.cnblogs.com/leleroyn/p/1935676.html
Copyright © 2020-2023  润新知