文档章节

处理控制台事件消息

Tocy
 Tocy
发布于 2015/09/09 22:14
字数 1479
阅读 4
收藏 0

处理控制台消息

作者:Tocy    时间:2012-05-25

1. 问题和需求描述

原有一个visual studio Win32 Console Application(传说中的控制台程序)开发的程序,由于程序本身有类似死循环的机制,也就是几乎一直运行,除非强制关闭那种。我们都知道如果直接关闭控制台,程序是可以结束的,但是这种结束是以程序异常结束为代价的(如果不相信,你可以写个死循环程序试试,将程序输出重定位到文件中,防止你看不到程序本身的输出,至于验证,我想你自己应该有思路的。)。那么该如何让程序正常结束呢?或者希望在控制台关闭的时候做一些处理,可能是给另外一个程序发送一个消息。那么又该怎么处理或者捕获控制台的退出事件呢?

问题到此问题,需求也基本是希望捕获控制台事件,比如关闭,比如按Ctrl+C退出等等。

(如果你对这个问题感兴趣,可以继续看下去,没有的话,就到此为止吧:-D)。

 

2. 解决方案

控制台处理函数(Console Control Handlers)

链接:http://msdn.microsoft.com/en-us/library/windows/desktop/ms682066(v=vs.85).aspx

每个控制台进程都有单独的控制处理函数列表,通常调用这些函数发生在控制台进程接收到ctrl+c、ctrl+break、ctrl+close信号。默认情况下控制处理函数列表中只有一个处理函数,其会调用ExitProcess。一个控制台进程可以使用SetConsoleCtrlHandler函数来添加或者删除额外的HandlerRoutine。这并不会对其他进程的控制台处理函数列表造成影响。系统丢用控制处理函数的顺序是按照最后注册首先调用的原则(栈),直到针对某控制信号的处理函数返回TRUE为止。如果所有处理函数都没有返回TRUE,就调用默认的处理函数(注:处理函数handler)。

(1)HandlerRoutine

声明格式如下:

BOOL WINAPI HandlerRoutine(

__in DWORD dwCtrlType // 控制事件类型

);

该函数只有一个参数,表示控制台发生什么消息。参数的具体值如表1所示:

表格 1 HandlerRoutine参数值及其意义

消息(宏)

实际值

意义

CTRL_C_EVENT

0

收到ctrl+c信号,来自键盘输入或者GenerateConsoleCtrlEvent函数产生的模拟信号

CTRL_BREAK_EVENT

1

收到ctrl+break信号,来自键盘输入或者GenerateConsoleCtrlEvent函数产生的模拟信号

CTRL_CLOSE_EVENT

2

控制台关闭信号,用户点击控制台标题栏上的关闭按钮或者使用任务管理器结束控制台进程。

CTRL_LOGOFF_EVENT

5

用户切换或者用户注销的信号。

CTRL_SHUTDOWN_EVENT

6

操作系统关闭时发送的信号。

通常我们处理的是前三个消息,如果有对后面两个消息感兴趣的情查看msdn,网址如下:

http://msdn.microsoft.com/en-us/library/windows/desktop/ms683242(v=vs.85).aspx

这里说明下返回值,如果该函数处理了某个信号,函数返回值必须为TRUE(也就是说不希望其他函数再处理这种信号),如果返回值为FALSE,那么该进程处理函数列表中的其他函数还会继续处理该信号。

CTRL_CLOSE_EVENT, CTRL_LOGOFF_EVENT和CTRL_SHUTDOWN_EVENT通常被用来处理一些程序的清理工作,然后调用ExitProcess API。另外,这三个事件有超时机制,CTRL_CLOSE_EVENT是5秒,另外两个是20秒。如果程序超时候,系统将会弹出结束进程的对话框。如果用户选择了结束进程,任何清理工作都不会做,所以应该在超时时间内完成工作。

 

(2)安装事件钩子,建立回调函数

——SetConsoleCtrlHandler

看这个函数的名字,基本上可以确定这是处理控制台相关函数,看看msdn说明。

原型如下:

BOOL SetConsoleCtrlHandler(

PHANDLER_ROUTINE HandlerRoutine, // 回调函数

BOOL Add // 表示添加还是删除

);

函数用法很明显。如果函数执行成功,返回非零值,失败则返回0。

msdn地址:http://msdn.microsoft.com/en-us/library/windows/desktop/ms686016(v=vs.85).aspx

 

下面是微软给的例子:

 

#include <windows.h>

#include <stdio.h>

 

BOOL CtrlHandler( DWORD fdwCtrlType )

{

switch( fdwCtrlType )

{

// Handle the CTRL-C signal.

case CTRL_C_EVENT:

printf( "Ctrl-C event\n\n" );

Beep( 750, 300 );

return( TRUE );

 

// CTRL-CLOSE: confirm that the user wants to exit.

case CTRL_CLOSE_EVENT:

Beep( 600, 200 );

printf( "Ctrl-Close event\n\n" );

return( TRUE );

 

// Pass other signals to the next handler.

case CTRL_BREAK_EVENT:

Beep( 900, 200 );

printf( "Ctrl-Break event\n\n" );

return FALSE;

 

case CTRL_LOGOFF_EVENT:

Beep( 1000, 200 );

printf( "Ctrl-Logoff event\n\n" );

return FALSE;

 

case CTRL_SHUTDOWN_EVENT:

Beep( 750, 500 );

printf( "Ctrl-Shutdown event\n\n" );

return FALSE;

 

default:

return FALSE;

}

}

 

int main( void )

{

if( SetConsoleCtrlHandler( (PHANDLER_ROUTINE) CtrlHandler, TRUE ) )

{

printf( "\nThe Control Handler is installed.\n" );

printf( "\n -- Now try pressing Ctrl+C or Ctrl+Break, or" );

printf( "\n try logging off or closing the console...\n" );

printf( "\n(...waiting in a loop for events...)\n\n" );

 

while( 1 ){ }

}

else

{

printf( "\nERROR: Could not set control handler");

return 1;

}

return 0;

}

 

个人认为下面代码还有点意思,如何在关闭控制台的时候的时候通知运行程序结束。

//

// setConsole_main.cpp

// 控制台消息处理

//

 

#include <STDIO.H>

#include <Windows.h>

 

HANDLE hExit = NULL;

 

void run()

{

    hExit = CreateEvent(NULL,TRUE,FALSE,"Test001");

 

    WaitForSingleObject(hExit,INFINITE);

}

 

BOOL HandlerRounte(DWORD dwCtrlType)

{

    BOOL Result = FALSE;

 

    printf("Start now...\r\n");

 

    switch(dwCtrlType)

    {

    case CTRL_C_EVENT:// ctrl + c

    case CTRL_BREAK_EVENT:// ctrl + break

    case CTRL_CLOSE_EVENT:// 关闭控制台

        Result = SetEvent(hExit); // 如果操作成功,则返回非零值,否则为0

        printf("(如果操作成功,则返回非零值,否则为0)---%d\r\n",Result);

        return TRUE;    

    default:

        return FALSE;

    }

    return FALSE;

}

 

void main()

{

    BOOL Result = FALSE;

    Result = SetConsoleCtrlHandler((PHANDLER_ROUTINE)HandlerRounte,TRUE);

    if(Result == TRUE)

    {

        run();

    }

}

到此为止,我们基本可以控制控制台的退出事件了,当然还有系统注销、用户切换或者系统关机其他控制台事件,最初的问题也基本解决。

关键词:SetConsoleCtrlHandler,控制台事件

注:版权所有,请勿用于商业用途,转载请注明原文地址。本人保留所有权利。

© 著作权归作者所有

Tocy
粉丝 29
博文 50
码字总数 59635
作品 0
海淀
程序员
私信 提问
JavaScript 事件循环详解(翻译)

最近在搜索更详细的关于JS事件处理的资料。发现国内的大部分blog都是相互抄袭。而MDM对于这里的解释也并不多。翻阅了部分文章,发现这篇文章很有价值。故译之。 原文:The JavaScript Event ...

YaHuiLiang(Ryou)
2018/07/25
0
0
【新功能发布】事件监控升级-支持自动化处理云产品异常

背景 系统事件监控为用户提供各类云产品产生的系统事件的统一统计和查询入口,使得用户明确知晓云产品的使用状态,让云更透明。 事件监控详细介绍 ECS 事件介绍及应对建议 本月的新版本,支持...

江米
2018/08/06
0
0
Chrome插件开发

Chrome的消息传递,可以在Web(通过content script)和扩展之间进行,任意一方都可发送或接收消息。Web(通过content script)发送消息如下: chrome.runtime.sendMessage({greeting: "hello...

brivio
2014/03/22
2.7K
0
Spring Cloud入门教程(十):消息总线(Bus)

Spring Cloud入门教程系列: Spring Cloud入门教程(一):服务治理(Eureka) Spring Cloud入门教程(二):客户端负载均衡(Ribbon) Spring Cloud入门教程(三):声明式服务调用(Feign) Spring Cl...

CD826
2018/05/22
0
0
如何在 Service Worker 和网页客户端之间发送消息

Service Workers 是一个为页面工作的后台处理器。提供离线web apps是Service Workers目前最让人感兴趣的功能,同时Service Workers能够管理一个本地的资源缓存,当网络连接状态是正常的时候,...

violinux666
01/02
2.5K
3

没有更多内容

加载失败,请刷新页面

加载更多

SpringBoot中 集成 redisTemplate 对 Redis 的操作(二)

SpringBoot中 集成 redisTemplate 对 Redis 的操作(二) List 类型的操作 1、 向列表左侧添加数据 Long leftPush = redisTemplate.opsForList().leftPush("name", name); 2、 向列表右......

TcWong
今天
4
0
排序––快速排序(二)

根据排序––快速排序(一)的描述,现准备写一个快速排序的主体框架: 1、首先需要设置一个枢轴元素即setPivot(int i); 2、然后需要与枢轴元素进行比较即int comparePivot(int j); 3、最后...

FAT_mt
昨天
4
0
mysql概览

学习知识,首先要有一个总体的认识。以下为mysql概览 1-架构图 2-Detail csdn |简书 | 头条 | SegmentFault 思否 | 掘金 | 开源中国 |

程序员深夜写bug
昨天
10
0
golang微服务框架go-micro 入门笔记2.2 micro工具之微应用利器micro web

micro web micro 功能非常强大,本文将详细阐述micro web 命令行的功能 阅读本文前你可能需要进行如下知识储备 golang分布式微服务框架go-micro 入门笔记1:搭建go-micro环境, golang微服务框架...

非正式解决方案
昨天
8
0
前端——使用base64编码在页面嵌入图片

因为页面中插入一个图片都要写明图片的路径——相对路径或者绝对路径。而除了具体的网站图片的图片地址,如果是在自己电脑文件夹里的图片,当我们的HTML文件在别人电脑上打开的时候图片则由于...

被毒打的程序猿
昨天
9
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部