Handle CTRL+C on Win32

The following code works for me:

#include <windows.h> 
#include <stdio.h> 

BOOL WINAPI consoleHandler(DWORD signal) {

    if (signal == CTRL_C_EVENT)
        printf("Ctrl-C handled\n"); // do cleanup

    return TRUE;
}

int main()
{
    running = TRUE;
    if (!SetConsoleCtrlHandler(consoleHandler, TRUE)) {
        printf("\nERROR: Could not set control handler"); 
        return 1;
    }

    while (1) { /* do work */ }

    return 0;
}

According to the documentation, when the handler (which is declared wrong, BTW) receives a CTRL_CLOSE_EVENT, CTRL_LOGOFF_EVENT, or CTRL_SHUTDOWN_EVENT signal, the process is terminated after the handler exits. To do what you are attempting, you are supposed to move your cleanup code into the handler itself.


Depending on your specific requirements you have a number of options. If you simply want to ignore Ctrl+C you can call SetConsoleCtrlHandler passing NULL as the HandlerRoutine parameter:

int _tmain(int argc, _TCHAR* argv[])
{
    SetConsoleCtrlHandler(NULL, TRUE);

    // do work

    return 0;
}

This removes all signal handlers. To terminate this application you have to implement custom logic to determine when to shut down.

If you want to handle Ctrl+C you have two options: Set up a handler for the signal or pass the keyboard input on to regular keyboard handling.

Setting up a handler is similar to the code above, but instead of passing NULL as the handler you provide your own implementation.

#include <windows.h>
#include <stdio.h>

volatile bool isRunnung = true;

BOOL WINAPI HandlerRoutine(_In_ DWORD dwCtrlType) {
    switch (dwCtrlType)
    {
    case CTRL_C_EVENT:
        printf("[Ctrl]+C\n");
        isRunnung = false;
        // Signal is handled - don't pass it on to the next handler
        return TRUE;
    default:
        // Pass signal on to the next handler
        return FALSE;
    }
}


int _tmain(int argc, _TCHAR* argv[])
{
    SetConsoleCtrlHandler(HandlerRoutine, TRUE);

    printf("Starting\n");
    while ( isRunnung ) {
        Sleep(0);
    }
    printf("Ending\n");

   return 0;
}

The output of this application is:

Starting
[Ctrl]+C
Ending

Note that cleanup code is executed, regardless of the code inside the main while-loop. Signal handlers form a linked list, where the handler functions are called on a last-registered, first-called basis until one of the handlers returns TRUE. If none of the handlers returns TRUE, the default handler is called. The default handler for a console calls ExitProcess when processing Ctrl+C.

If you want to prevent any preprocessing and handle Ctrl+C as regular keyboard input instead you have to change the console mode by calling SetConsoleMode.

#include <windows.h>
#include <stdio.h>

int _tmain(int argc, _TCHAR* argv[])
{
    DWORD dwMode = 0x0;
    GetConsoleMode( GetStdHandle(STD_INPUT_HANDLE), &dwMode );
    // Remove ENABLE_PROCESSED_INPUT flag
    dwMode &= ~ENABLE_PROCESSED_INPUT;
    SetConsoleMode( GetStdHandle(STD_INPUT_HANDLE), dwMode );

    while ( true ) {
        // Ctrl+C can be read using ReadConsoleInput, etc.
    }

    return 0;
}

Once the ENABLE_PROCESSED_INPUT flag is removed Ctrl+C is no longer processed by the system and passed to the console like regular keyboard input. It can be read using ReadConsoleInput or ReadFile.

Disclaimer: The above has been tested on Windows 8 64bit, compiled for 32 and 64 bit, Release and Debug configurations.