ean*_*ang 12 c++ winapi console-application
我在Win32 C++控制台程序中处理CTRL+ C事件时遇到了一些问题.
基本上我的程序看起来像这样:(基于另一个问题:Windows Ctrl-C - 在命令行应用程序中清理本地堆栈对象)
bool running;
int main() {
running = true;
SetConsoleCtrlHandler((PHANDLER_ROUTINE) consoleHandler, TRUE);
while (running) {
// do work
...
}
// do cleanup
...
return 0;
}
bool consoleHandler(int signal) {
if (signal == CTRL_C_EVENT) {
running = false;
}
return true;
}
Run Code Online (Sandbox Code Playgroud)
问题是根本没有执行清理代码.
执行处理程序函数后,进程终止,但不执行主循环后的代码.怎么了?
编辑:根据要求,这是一个类似于我的程序的最小测试用例:http://pastebin.com/6rLK6BU2
我的输出中没有得到"test cleanup-instruction"字符串.
我不知道这是否重要,我正在与MinGW进行编译.
编辑2:测试用例程序的问题是使用该Sleep()
功能.没有它,程序按预期工作.
在Win32中,函数处理程序在另一个线程中运行,因此当处理程序/线程结束其执行时,主线程正在休眠.可能这是过程中断的原因?
lpa*_*app 10
以下代码适用于我:
#include <windows.h>
#include <stdio.h>
BOOL WINAPI consoleHandler(DWORD signal) {
if (signal == CTRL_C_EVENT)
printf("Ctrl-C handled\n"); // do cleanup
return TRUE;
}
int main()
{
running = TRUE;
if (!SetConsoleCtrlHandler(consoleHandler, TRUE)) {
printf("\nERROR: Could not set control handler");
return 1;
}
while (1) { /* do work */ }
return 0;
}
Run Code Online (Sandbox Code Playgroud)
根据您的具体要求,您有多种选择.如果你只是想忽略Ctrl+ C你可以调用SetConsoleCtrlHandler
传递NULL
作为HandlerRoutine
参数:
int _tmain(int argc, _TCHAR* argv[])
{
SetConsoleCtrlHandler(NULL, TRUE);
// do work
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这将删除所有信号处理程序.要终止此应用程序,您必须实现自定义逻辑以确定何时关闭.
如果你想处理Ctrl+ C你有两个选择:为信号设置处理程序或将键盘输入传递给常规键盘处理.
设置处理程序与上面的代码类似,但不是NULL
作为处理程序传递,而是提供自己的实现.
#include <windows.h>
#include <stdio.h>
volatile bool isRunnung = true;
BOOL WINAPI HandlerRoutine(_In_ DWORD dwCtrlType) {
switch (dwCtrlType)
{
case CTRL_C_EVENT:
printf("[Ctrl]+C\n");
isRunnung = false;
// Signal is handled - don't pass it on to the next handler
return TRUE;
default:
// Pass signal on to the next handler
return FALSE;
}
}
int _tmain(int argc, _TCHAR* argv[])
{
SetConsoleCtrlHandler(HandlerRoutine, TRUE);
printf("Starting\n");
while ( isRunnung ) {
Sleep(0);
}
printf("Ending\n");
return 0;
}
Run Code Online (Sandbox Code Playgroud)
该应用程序的输出是:
Starting
[Ctrl]+C
Ending
Run Code Online (Sandbox Code Playgroud)
请注意,无论main while
-loop 中的代码如何,都会执行清理代码.信号处理程序形成一个链表,其中处理程序函数在最后注册的,第一次调用的基础上调用,直到其中一个处理程序返回TRUE
.如果没有处理程序返回TRUE,则调用默认处理程序.ExitProcess
处理Ctrl+ 时,控制台的默认处理程序调用C.
如果你想阻止任何预处理和处理Ctrl+ C作为常规键盘输入,你必须通过调用来改变控制台模式SetConsoleMode
.
#include <windows.h>
#include <stdio.h>
int _tmain(int argc, _TCHAR* argv[])
{
DWORD dwMode = 0x0;
GetConsoleMode( GetStdHandle(STD_INPUT_HANDLE), &dwMode );
// Remove ENABLE_PROCESSED_INPUT flag
dwMode &= ~ENABLE_PROCESSED_INPUT;
SetConsoleMode( GetStdHandle(STD_INPUT_HANDLE), dwMode );
while ( true ) {
// Ctrl+C can be read using ReadConsoleInput, etc.
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
一旦ENABLE_PROCESSED_INPUT
标记被去掉Ctrl+ C由系统不再处理并传递到像普通键盘输入控制台.它可以使用ReadConsoleInput
或读取ReadFile
.
免责声明:以上内容已在Windows 8 64位上进行了测试,针对32位和64位,发布和调试配置进行了编译.
实际上,Win32 对 POSIX 信号有一些模拟,因此您可以执行以下操作,这将在 Windows 和 POSIX(Linux、*BSD 等)之间移植:
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
static void sigHandler(int sig) {
printf("Signal %d received, exiting\n", sig);
exit(0);
};
int main() {
signal(SIGINT, sigHandler);
#ifdef SIGBREAK
signal(SIGBREAK, sigHandler); // handles Ctrl-Break on Win32
#endif
signal(SIGABRT, sigHandler);
signal(SIGTERM, sigHandler);
printf("Press Ctrl-C to exit ...\n");
for (;;) {
getchar();
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
17870 次 |
最近记录: |