I'm trying to get GenerateConsoleCtrlEvent
to work. This is the minimal example I've come up with:
#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;
}
So I start it up, type in something (no newline), and wait 10 seconds. The debugger shows the Ctrl-C event. The console shows that the Ctrl-C had no effect.
I tracked down the issue to this: the main cmd.exe thread calls ReadConsoleW
. Under the test program with GenerateConsoleCtrlEvent
, this does not return. Pressing Ctrl-C does make it return, with *lpNumberOfCharsRead==0
.
GenerateConsoleCtrlEvent
starts a new thread using kernel32!CtrlRoutine
. If, using the debugger, you freeze this thread, cmd.exe still behaves as if Ctrl-C was pressed. In fact, you can trick cmd.exe into believing that there is was a Ctrl-C pressed if you set *lpNumberOfCharsRead==NULL
when ReadConsoleW
returns after a return keypress.
cmd.exe
is not unique in the behavior: Python.exe's read returns immediately upon Ctrl-C, but not upon GenerateConsoleCtrlEvent
. Python.exe uses ReadFile
. (Python.exe notices the KeyboardInterrupt after you press enter.)
So the question is: why does ReadConsoleW
return immediately when you press Ctrl-C, but not when GenerateConsoleCtrlEvent
is called? As far as I can tell, on Windows 7, pressing Ctrl-C sends messages that are read by conhost.exe
which communicates with csrss.exe
, which calls NtCreateThreadEx
with kernel32!CtrlRoutine
. I do not see that it does anything else when you press Ctrl-C. But what is causing ReadConsoleW
to return?