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?