SetConsoleCtrlHandler does not get called on shutdown

試著忘記壹切 提交于 2021-02-19 02:22:55

问题


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

My test application writes a file with the signal and works when the console window is closed by hand (click on the X). But it does not work when the console is closed on shutdown or logout. From what I have read on MSDN, this should work.

The program was compiled using cygwin64, could this be the 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;
}

回答1:


ok, since the program is intended to run in background, I implemented it as a windows service. On windows shutdown, the service will receive SERVICE_CONTROL_SHUTDOWN. The service can be installed with the sc.exe program or even programmatically.

#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;
}


来源:https://stackoverflow.com/questions/27162884/setconsolectrlhandler-does-not-get-called-on-shutdown

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!