调试win32控制台的程序的时候,发现直接点击控制台(传说中的黑框框)的右上角的叉退出的时候很多时候程序都没有办法进行收尾处理
比如文件操作的时候,fopen了文件如果直接叉掉控制台导致没有fclose文件从而最后写入文件的一批数据没有保存到硬盘;又比如多线程的程序如果直接叉掉控制台将有可能导致线程无法退出的情况
这个时候我们就可以使用SetConsoleCtrHandler来处理控制台消息
SetConsoleCtrHandler是一个WIN32 API
函数原型:
BOOL SetConsoleCtrlHandler(
PHANDLER_ROUTINE HandlerRoutine, //回调函数
BOOL Add // 表示添加还是删除
);
返回值:BOOL类型
参数
参数HandlerRoutine:一个应用程序定义的指针HandlerRoutine 功能要添加或删除。这个参数可以是NULL。
参数Add:如果此参数为TRUE,添加回调函数,如果是FALSE,删除回调函数。
返回值:
如果函数失败,返回值为0;否则,返回一个非0值。 若想获得更多错误信息,调用GetLastError函数 。
说白了,就是一个系统调用。
第一个参数是函数指针,就是上面的那个函数。第二个参数是标志,如果为TRUE那么就安装钩子,如果为FALSE那么删除钩子。
接下来看看例程
#include <stdio.h>
#include "windows.h"
BOOL WINAPI HandlerRoutine(DWORD dwCtrlType);
FILE *fp;
int main(int argc, char* argv[])
{
char l_cTemp = ' ';
fp = NULL;
//控制台异常退出事件
SetConsoleCtrlHandler(HandlerRoutine, TRUE);
fp = fopen("test.txt", "at+");
while(1)
{
scanf("%c", &l_cTemp);
if('q' == l_cTemp)
{
fprintf(fp, "normal exit\n");
fclose(fp);
fp = NULL;
break;
}
}
}
BOOL WINAPI HandlerRoutine(DWORD dwCtrlType)
{
// 控制台将要被关闭
if(CTRL_CLOSE_EVENT == dwCtrlType)
{
fprintf(fp, "unexpected exit\n");
fclose(fp);
fp = NULL;
}
return TRUE;
}
这个例程通过文件操作来展示控制台消息的回调函数的运行。
首先在main函数之前声明了一个回调函数,也就是钩子函数:
BOOL WINAPI HandlerRoutine(DWORD dwCtrlType);
在main函数之后实现了该函数:
BOOL WINAPI HandlerRoutine(DWORD dwCtrlType)
{
// 控制台将要被关闭
if(CTRL_CLOSE_EVENT == dwCtrlType)
{
fprintf(fp, "unexpected exit\n");
fclose(fp);
fp = NULL;
}
return TRUE;
}
回调函数中对获取到的消息dwCtrlType进行判断,参数有下列值:
CTRL_C_EVENT - 当用户按下了CTRL+C,或者由GenerateConsoleCtrlEvent API发出.
CTRL_BREAK_EVENT - 用户按下CTRL+BREAK, 或者由GenerateConsoleCtrlEvent API发出.
CTRL_CLOSE_EVENT - 当试图关闭控制台程序,系统发送关闭消息。
CTRL_LOGOFF_EVENT - 用户退出时,但是不能决定是哪个用户.
CTRL_SHUTDOWN_EVENT - 当系统被关闭时.
这里只对CTRL_CLOSE_EVENT做了处理,也就是当用户试图关闭控制台程序时回调函数会进入if处理,即在文件中写入字符串“unexpected exit”,然后关闭文件并退出。
再看main函数中的实现,这里通过SetConsoleCtrlHandler函数加载或者移除回调函数:
//控制台异常退出事件
SetConsoleCtrlHandler(HandlerRoutine, TRUE);
第一个参数为回调函数名;第二个参数表示加载或者移除回调函数,为TRUE表示加载回调函数,为FALSE表示移除回调函数。
这样就完成了控制台消息回调函数的编写;
剩下的就是创建文件并在用户正确输入‘q’字符后往文件中写入字符串“normal exit”,然后关闭文件并正常退出。
然后运行程序,当我们在控制台中输入‘q’字符并回车,生成的test.txt文件中被写入字符串“normal exit”;
再次运行程序,然后我们直接通过右上角的叉关掉控制台后,生成的test.txt文件中被写入字符串“unexpected exit”。
参考链接:
http://andylin02.iteye.com/blog/661431
http://bbs.csdn.net/topics/390764438