我正在努力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
when ReadConsoleW
return after a return keypress,你可以欺骗cmd.exe相信有一个Ctrl-C被按下。
cmd.exe
行为不是唯一的:Python.exe 的读取在 Ctrl-C 时立即返回,但不是在GenerateConsoleCtrlEvent
. Python.exe 使用ReadFile
. (Python.exe 在您按下 Enter 后会注意到 KeyboardInterrupt。)
所以问题是:为什么ReadConsoleW
当你按下 Ctrl-C 时立即返回,而不是在GenerateConsoleCtrlEvent
被调用时?据我所知,在 Windows 7 上,按 Ctrl-C 会发送消息,这些消息由conhost.exe
which 与 通信csrss.exe
、NtCreateThreadEx
与kernel32!CtrlRoutine
. 当您按 Ctrl-C 时,我看不到它会执行任何其他操作。但是是什么导致ReadConsoleW
返回?