我正试图让GenerateConsoleCtrlEvent
工作。这是我提出的最小例子:
#include <Windows.h>
static BOOL WINAPI handler(DWORD CtrlType)
{
return TRUE;
}
int main()
{
if (!SetConsoleCtrlHandler(&handler, TRUE))
{
throw 1;
}
STARTUPINFO si = {0};
DWORD dwStartupFlags = 0;
PROCESS_INFORMATION pi;
if (!CreateProcess(
NULL,
"cmd.exe",
NULL,
NULL,
FALSE,
dwStartupFlags,
NULL, // environ
NULL, // cwd
&si,
&pi))
{
throw 1;
}
CloseHandle(pi.hThread);
DWORD exitCode;
while(true)
{
switch (WaitForSingleObject(pi.hProcess, 1000 * 10))
{
case WAIT_TIMEOUT:
GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0);
//WaitForSingleObject(pi.hProcess, INFINITE);
break;
case WAIT_OBJECT_0:
GetExitCodeProcess(pi.hProcess, &exitCode);
return exitCode;
}
}
return -1;
}
所以我启动它,输入内容(没有换行符),然后等待10秒钟。调试器显示Ctrl-C事件。控制台显示Ctrl-C无效。
我跟踪了这个问题:主cmd.exe线程调用ReadConsoleW
。在GenerateConsoleCtrlEvent
的测试程序下,这不会返回。按下Ctrl-C会使其返回*lpNumberOfCharsRead==0
。
GenerateConsoleCtrlEvent
使用kernel32!CtrlRoutine
启动新主题。如果使用调试器冻结此线程,cmd.exe仍然表现得像按Ctrl-C一样。实际上,如果在返回按键后*lpNumberOfCharsRead==NULL
返回时设置ReadConsoleW
,则可以欺骗cmd.exe,使其相信已按下Ctrl-C。
cmd.exe
在行为上不是唯一的:Python.exe的读取在Ctrl-C时立即返回,但在GenerateConsoleCtrlEvent
时不返回。 Python.exe使用ReadFile
。 (按下回车键后,Python.exe会注意到KeyboardInterrupt。)
所以问题是:为什么在按下Ctrl-C时ReadConsoleW
会立即返回,而在调用GenerateConsoleCtrlEvent
时却不会?据我所知,在Windows 7上,按Ctrl-C会发送由conhost.exe
读取的消息,该消息与csrss.exe
进行通信,NtCreateThreadEx
调用kernel32!CtrlRoutine
ReadConsoleW
。按Ctrl-C时,我没有看到它做任何其他事情。但导致{{1}}返回的原因是什么?