SetConsoleCtrlHandler is not called when shutting down

I wrote an application that runs in the console and must perform a quick backup before the system shuts down or the user logs out.

My test application writes a signal file and works when the console window is closed manually (click on X). But this does not work when the console closes when shutting down or exiting the system. From what I read on MSDN, this should work.

The program was compiled using cygwin64, could this be a problem?

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

BOOL WINAPI myHandler(DWORD signal) {
    switch(signal) {
        case CTRL_C_EVENT:
            printf("ctrl-c\n");
            break;
        case CTRL_BREAK_EVENT:
            printf("break\n");
            break;
        default:
            printf("Some other event\n");
    }

    FILE *file = fopen("windows_sig.txt", "w");
    fprintf(file, "got signal: %d\n", signal);
    fclose(file);

    return TRUE;
}

int main(int argc, char *argv[])
{
    if (!SetConsoleCtrlHandler((PHANDLER_ROUTINE)myHandler,TRUE)) {
        fprintf(stderr, "Unable to install handler!\n");
        return EXIT_FAILURE;
    }

    for (;;)
        ; //do nothing

    return EXIT_SUCCESS;
}
+4
source share
1 answer

ok, , Windows. Windows SERVICE_CONTROL_SHUTDOWN. ​​ sc.exe .

#include <windows.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>

static SERVICE_STATUS sStatus;
static SERVICE_STATUS_HANDLE hServiceStatus = 0;
static int is_running = 1;
static void (*svc_main_func)();


void windows_service_control( DWORD dwControl ) {
    switch (dwControl) {
        case SERVICE_CONTROL_SHUTDOWN:
        case SERVICE_CONTROL_STOP:
            sStatus.dwCurrentState = SERVICE_STOP_PENDING;
            sStatus.dwCheckPoint = 0;
            sStatus.dwWaitHint = 3000; /* Three seconds */
            sStatus.dwWin32ExitCode = 0;
            is_running = 0;
        default:
            sStatus.dwCheckPoint = 0;
    }
    SetServiceStatus( hServiceStatus, &sStatus );
}

void windows_service_main( int argc, char **argv ) {

    hServiceStatus = RegisterServiceCtrlHandler( argv[0], (LPHANDLER_FUNCTION) windows_service_control );
    if( hServiceStatus == 0 ) {
        return;
    }

    sStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
    sStatus.dwCurrentState = SERVICE_START_PENDING;
    sStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
    sStatus.dwWin32ExitCode = 0;
    sStatus.dwServiceSpecificExitCode = 0;
    sStatus.dwCheckPoint = 0;
    sStatus.dwWaitHint = 3000; /* Allow us to wait three seconds */
    sStatus.dwCurrentState = SERVICE_RUNNING;

    SetServiceStatus( hServiceStatus, &sStatus );

    /* The main program */
    svc_main_func();

    /* cleanup */
    sStatus.dwCurrentState  = SERVICE_STOPPED;
    SetServiceStatus( hServiceStatus, &sStatus );
}

int windows_service_start( void (*func)() ) {
    static SERVICE_TABLE_ENTRY services[] = {
        { MAIN_SRVNAME,  (LPSERVICE_MAIN_FUNCTIONA) windows_service_main },
        { NULL, NULL }
    };

    /* Safe args for later call in windows_service_main() */
    svc_main_func = func;

    if( !StartServiceCtrlDispatcher( services ) ) {
        printf( "Can not start service: Error %d\n", GetLastError() );
        return 1;
    } else {
        return 0;
    }
}

void run() {
  while(is_running) {
    //do work
  }
}

int main() {
  windows_service_start(run);
  return 0;
}
+2

All Articles