在 Win32 上处理 CTRL+C
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18291284/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Handle CTRL+C on Win32
提问by eang
I have some problems with the handling of CTRL+Cevents, in a Win32 C++console program.
在Win32 C++控制台程序中,我在处理CTRL+C事件时遇到了一些问题。
Basically my program looks like this: (based on this other question: Windows Ctrl-C - Cleaning up local stack objects in command line app)
基本上我的程序是这样的:(基于另一个问题:Windows Ctrl-C - Cleaning up local stack objects in command line app)
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;
}
The problem is the cleanup code not being executed at all.
问题是根本没有执行清理代码。
After the execution of the handler function the process is terminated, but without execute the code after the main loop. What's wrong?
处理程序函数执行后,进程终止,但不执行主循环后的代码。怎么了?
EDIT: as requested, this is a minimal test case similar to my program: http://pastebin.com/6rLK6BU2
编辑:根据要求,这是一个类似于我的程序的最小测试用例:http: //pastebin.com/6rLK6BU2
I don't get the "test cleanup-instruction" string in my output.
我的输出中没有“测试清理指令”字符串。
I don't know if this is important, I'm compiling with MinGW.
我不知道这是否重要,我正在使用MinGW 进行编译。
EDIT 2: The problem with the test case program is the use of the Sleep()
function. Without it the program works as expected.
编辑 2:测试用例程序的问题是Sleep()
函数的使用。没有它,程序会按预期工作。
In Win32 the function handler runs in another thread, so when the handler/thread ends its execution the main thread is sleeping. Probably this is the cause of process interruption?
在 Win32 中,函数处理程序在另一个线程中运行,因此当处理程序/线程结束其执行时,主线程正在休眠。大概这就是进程中断的原因?
采纳答案by lpapp
The following code works for me:
以下代码对我有用:
#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;
}
回答by Remy Lebeau
According to the documentation, when the handler (which is declared wrong, BTW) receives a CTRL_CLOSE_EVENT
, CTRL_LOGOFF_EVENT
, or CTRL_SHUTDOWN_EVENT
signal, the process is terminated after the handler exits. To do what you are attempting, you are supposed to move your cleanup code into the handler itself.
据的文档,当该处理程序(其被声明错误,顺便说一句)接收CTRL_CLOSE_EVENT
,CTRL_LOGOFF_EVENT
或CTRL_SHUTDOWN_EVENT
信号时,处理在处理程序退出后终止。要执行您正在尝试的操作,您应该将清理代码移动到处理程序本身中。
回答by IInspectable
Depending on your specific requirements you have a number of options. If you simply want to ignore Ctrl+Cyou can call SetConsoleCtrlHandler
passing NULL
as the HandlerRoutine
parameter:
根据您的具体要求,您有多种选择。如果你只是想忽略Ctrl+C你可以调用作为参数SetConsoleCtrlHandler
传递:NULL
HandlerRoutine
int _tmain(int argc, _TCHAR* argv[])
{
SetConsoleCtrlHandler(NULL, TRUE);
// do work
return 0;
}
This removes all signal handlers. To terminate this application you have to implement custom logic to determine when to shut down.
这将删除所有信号处理程序。要终止此应用程序,您必须实现自定义逻辑以确定何时关闭。
If you want to handle Ctrl+Cyou have two options: Set up a handler for the signal or pass the keyboard input on to regular keyboard handling.
如果您想处理Ctrl+,C您有两个选择:为信号设置处理程序或将键盘输入传递给常规键盘处理。
Setting up a handler is similar to the code above, but instead of passing NULL
as the handler you provide your own implementation.
设置处理程序类似于上面的代码,但不是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;
}
The output of this application is:
此应用程序的输出是:
Starting
[Ctrl]+C
Ending
Note that cleanup code is executed, regardless of the code inside the main while
-loop. Signal handlers form a linked list, where the handler functions are called on a last-registered, first-called basis until one of the handlers returns TRUE
. If none of the handlers returns TRUE, the default handler is called. The default handler for a console calls ExitProcess
when processing Ctrl+C.
请注意,无论主while
循环内的代码如何,都会执行清理代码。信号处理程序形成一个链表,其中处理程序函数在最后注册、首先调用的基础上被调用,直到其中一个处理程序返回TRUE
。如果没有处理程序返回 TRUE,则调用默认处理程序。ExitProcess
处理Ctrl+时控制台调用的默认处理程序C。
If you want to prevent any preprocessing and handle Ctrl+Cas regular keyboard input instead you have to change the console mode by calling SetConsoleMode
.
如果要防止任何预处理并将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;
}
Once the ENABLE_PROCESSED_INPUT
flag is removed Ctrl+Cis no longer processed by the system and passed to the console like regular keyboard input. It can be read using ReadConsoleInput
or ReadFile
.
一旦ENABLE_PROCESSED_INPUT
标记被去掉Ctrl+C不再由系统处理并传递给像普通键盘输入控制台。可以使用ReadConsoleInput
或读取它ReadFile
。
Disclaimer: The above has been tested on Windows 8 64bit, compiled for 32 and 64 bit, Release and Debug configurations.
免责声明:以上已在 Windows 8 64 位上测试,针对 32 位和 64 位编译,发布和调试配置。