5

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?

Kevin Smyth
  • 1,892
  • 21
  • 22
  • The SetConsoleMode() winapi function, ENABLE_PROCESSED_INPUT option flag is relevant. It allows a program to specify whether it wants to see Ctrl+C itself or leave it up to the system to handle it. This flag is definitely off for cmd.exe. Since pressing Ctrl+C doesn't terminate it. – Hans Passant Sep 02 '13 at 15:47
  • try starting something besides cmd.exe then I guess? See also http://stackoverflow.com/questions/813086/can-i-send-a-ctrl-c-sigint-to-an-application-on-windows – rogerdpack Jun 23 '15 at 00:17
  • In the test program, if you swap `cmd.exe` with `Python.exe`, it behaves similarly: the `GenerateConsoleCtrlEvent` has no immediate effect, but `Python.exe`notices the Ctrl+C after you press enter. I don't think `cmd.exe` is unique here. – Kevin Smyth Jun 23 '15 at 16:58

0 Answers0