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

转自:http://www.cnblogs.com/birdshover/archive/2008/03/18/1110138.html

控制台程序足够简洁,但是,经常会点错而误关闭。而且,如果系统关闭,或者用户注销,这时候任务还没完成的话,前面的运算电费就白出了。

有没有办法和WinForm一样,对控制台的退出事件进行控制呢?有的!

引入下面的函数
1         public delegate bool HandlerRoutine(int dwCtrlType);
2 
3         [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
4         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,也就是说,这个时候会关闭。但是在关闭之前我们可以做一些操作。

试想这样的情况,这个任务可能需要运行很长时间,要能在程序关闭的时候有个保存当前进度的方法,那么就可以采用以上操作了。

来看个完整的代码

 1     class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             Program p = new Program();
 6             if (!SetConsoleCtrlHandler(p.HandlerRoutineMethod, true))
 7             {
 8                 Console.WriteLine("无法注册系统事件!\n");
 9             }
10 
11             while (true)
12             {
13                 string s = Console.ReadLine();
14                 if (s == "exit")
15                     GenerateConsoleCtrlEvent(p.CTRL_BREAK_EVENT0);
16             }
17         }
18 
19         const int CTRL_C_EVENT = 0;
20         const int CTRL_BREAK_EVENT = 1;
21         const int CTRL_CLOSE_EVENT = 2;
22         const int CTRL_LOGOFF_EVENT = 5;
23         const int CTRL_SHUTDOWN_EVENT = 6;
24 
25         public bool HandlerRoutineMethod(int dwCtrlType)
26         {
27             Console.WriteLine(dwCtrlType.ToString());
28             switch (dwCtrlType)
29             {
30                 case CTRL_C_EVENT:
31                     return true;
32                 case CTRL_BREAK_EVENT:
33                     Save();
34                     return false;
35                 case CTRL_CLOSE_EVENT:
36                     Console.WriteLine("确实要退出程序么?如果需要退出,请输入'exit'。");
37                     return true;
38                 case CTRL_LOGOFF_EVENT:
39                     //用户退出
40                     Save();
41                     return false;
42                 case CTRL_SHUTDOWN_EVENT:
43                     //系统关闭
44                     Save();
45                     return false;
46             }
47             return true;
48         }
49 
50         void Save()
51         {
52                  //保存当前进度
53         }
54 
55         public delegate bool HandlerRoutine(int dwCtrlType);
56 
57         [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
58         public static extern bool SetConsoleCtrlHandler(HandlerRoutine HandlerRoutine, bool add);
59 
60         [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
61         public static extern bool GenerateConsoleCtrlEvent(int code, int value);
62     }

先 是用SetConsoleCtrlHandler方法,设置了HandlerRoutineMethod为他的回调函数。那么当有事件过来的时候,会先调用这个方法。这个方法return false,则窗体关闭,true,则窗体不关闭。


GenerateConsoleCtrlEvent方法是通知系统事件的。我们这里假设,只有用户输入exit,或者按Ctrl+Break的时候程序退出。对于用户退出和系统关闭,只是保存当前进度。

while 循环中,如果用户输入exit命令,则通知系统调用回调函数HandlerRoutineMethod,调用的事件是Ctrl+Break。

现在控制台是不是比以前好用了很多呢?:)

全文完。 by yurow.

 

posted @ 2008-05-21 15:33  元宝  阅读(1742)  评论(0编辑  收藏  举报
我最爱的地质软件?!……