windows – 关闭时不调用SetConsoleCtrlHandler

我编写了一个在控制台中运行的应用程序,需要在系统关闭或用户注销之前进行快速备份.

我的测试应用程序使用信号写入文件,并在手动关闭控制台窗口时工作(单击X).但是在关闭或注销时关闭控制台时它不起作用.从我在MSDN上看到的,这应该工作.

该程序是使用cygwin64编译的,这可能是问题吗?

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

最佳答案 好吧,因为该程序是在后台运行,我将其实现为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;
}
点赞