【问题标题】:Windows service does not capture shutdown event C/C++Windows 服务不捕获关机事件 C/C++
【发布时间】:2020-05-22 23:17:33
【问题描述】:

我创建了一个小型 Windows 服务来捕获一些事件,包括系统关闭。每次我关闭计算机时,服务事件都不会被调用。但是当我重新启动计算机时,该事件正常工作。

我已经尝试使用:SERVICE_ACCEPT_PRESHUTDOWN + SERVICE_CONTROL_PRESHUTDOWN,但没有成功。

我怎样才能捕捉到计算机关机事件?

Ps:编译后我使用以下命令注册服务:sc.exe create "ZSimpleService" binPath = "C:\path\ZSimpleService.exe"

编辑 1:我使用的是 Windows 10

代码:

SERVICE_STATUS g_ServiceStatus = { 0 };
SERVICE_STATUS_HANDLE g_StatusHandle = NULL;
HANDLE g_ServiceStopEvent = INVALID_HANDLE_VALUE;

VOID WINAPI ServiceMain(DWORD argc, LPTSTR *argv);
DWORD WINAPI ServiceWorkerThread(LPVOID lpParam);
DWORD WINAPI CtrlHandlerEx(DWORD CtrlCode, DWORD eventType, LPVOID eventData, LPVOID context);

#define SERVICE_NAME _T("ZSimpleService")

VOID WINAPI ServiceMain(DWORD argc, LPTSTR *argv) {

    g_StatusHandle = RegisterServiceCtrlHandlerEx(SERVICE_NAME, CtrlHandlerEx,
    NULL);

    if (g_StatusHandle == NULL) {
        goto EXIT;
    }

    // Tell the service controller we are starting
    ZeroMemory( & g_ServiceStatus, sizeof(g_ServiceStatus));

    g_ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
    g_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP
            | SERVICE_ACCEPT_POWEREVENT | SERVICE_ACCEPT_SESSIONCHANGE
            | SERVICE_ACCEPT_SHUTDOWN;
    g_ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
    g_ServiceStatus.dwWin32ExitCode = 0;
    g_ServiceStatus.dwServiceSpecificExitCode = 0;
    g_ServiceStatus.dwCheckPoint = 0;

    if (SetServiceStatus(g_StatusHandle, &g_ServiceStatus) == FALSE) {
        //...
    }

    g_ServiceStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

    if (g_ServiceStopEvent == NULL) {
        //...
        goto EXIT;
    }

    g_ServiceStatus.dwCurrentState = SERVICE_RUNNING;
    g_ServiceStatus.dwWin32ExitCode = 0;
    g_ServiceStatus.dwCheckPoint = 0;

    if (SetServiceStatus(g_StatusHandle, &g_ServiceStatus) == FALSE) {
        //...
    }

    HANDLE hThread = CreateThread(NULL, 0, ServiceWorkerThread, NULL, 0, NULL);

    WaitForSingleObject(hThread, INFINITE);

    CloseHandle(g_ServiceStopEvent);

    g_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
    g_ServiceStatus.dwWin32ExitCode = 0;
    g_ServiceStatus.dwCheckPoint = 3;

    if (SetServiceStatus(g_StatusHandle, &g_ServiceStatus) == FALSE) {

    }

    EXIT: return;
}

void suspending() {
    FILE *file = fopen("C:\\test\\suspending.txt", "w+");
    if (file)
        fprintf(file, "...");
}

void logoff() {
    FILE *file = fopen("C:\\test\\logoff.txt", "w+");
    if (file)
        fprintf(file, "...");
}

void lock_session() {
    FILE *file = fopen("C:\\test\\lock_session.txt", "w+");
    if (file)
        fprintf(file, "...");
}

void poweroff() {
    FILE *file = fopen("C:\\test\\poweroff.txt", "w+");
    if (file)
        fprintf(file, "...");
}

DWORD WINAPI CtrlHandlerEx(DWORD CtrlCode, DWORD eventType, LPVOID eventData,
        LPVOID context) {
    switch (CtrlCode) {

    case SERVICE_CONTROL_STOP: {
        g_ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
        g_ServiceStatus.dwWin32ExitCode = 0;
        g_ServiceStatus.dwCheckPoint = 0;
        g_ServiceStatus.dwWaitHint = 0;

        if (SetServiceStatus(g_StatusHandle, &g_ServiceStatus) == FALSE) {
            //...
        }

        SetEvent(g_ServiceStopEvent);

        return NO_ERROR;
    }
    case SERVICE_CONTROL_POWEREVENT: {
        if (eventType == PBT_APMQUERYSUSPEND) {
            //Computer is suspending
            suspending();

        }
        return NO_ERROR;
    }
    case SERVICE_CONTROL_SESSIONCHANGE: {
        switch (eventType) {
        case WTS_SESSION_LOGOFF:
            //User is logging off
            logoff();
            break;
        case WTS_SESSION_LOCK:
            //User locks the session
            lock_session();
            break;
        }
        return NO_ERROR;
    }
    case SERVICE_CONTROL_SHUTDOWN: {
        //Computer is shutting down
        poweroff();

        return NO_ERROR;
    }
    default:
        return ERROR_CALL_NOT_IMPLEMENTED;
    }

}

DWORD WINAPI ServiceWorkerThread(LPVOID lpParam) {

    while (WaitForSingleObject(g_ServiceStopEvent, 0) != WAIT_OBJECT_0) {

        //many cool code....

        Sleep(3000);
    }

    return 0;
}

DWORD RunService() {
    SERVICE_TABLE_ENTRY serviceTable[] = { { SERVICE_NAME, ServiceMain },
            { 0, 0 } };

    if (StartServiceCtrlDispatcher(serviceTable)) {
        return 0;
    } else {
        DWORD erro = GetLastError();

        //handler erro...

        return 1;
    }
}

int _tmain(int argc, TCHAR *argv[]) {
    RunService();
    return 0;
}

【问题讨论】:

  • 可能你的电脑真的不是关机而是休眠
  • 我从命令行关闭了 windows 1903:shutdown /s。它对我有用(创建 logoff.txt 和 poweroff.txt)。您如何关闭机器以及您的 Windows 版本是多少?
  • @RitaHan-MSFT 你好,我用关机命令试过了,它奏效了!但我不明白为什么在:开始菜单->关机/重启->关机。关机不起作用,我关机时别名CtrlHandlerEx收到:CtrlCode SERVICE_CONTROL_POWEREVENTeventType PBT_APMQUERYSUSPEND
  • 从事件查看器发现关闭菜单似乎在调用SetSuspendState API 以使机器进入睡眠模式,因此您不会收到SERVICE_CONTROL_SHUTDOWN 事件。

标签: c++ c winapi events service


【解决方案1】:

启用快速启动选项后​​,单击开始菜单->关机将使机器进入睡眠模式/休眠状态而不是关机。但重启菜单不受影响。 (我们已经发现,从命令行关闭也不会受到影响。)

所以你可以禁用快速启动来解决这个问题。

【讨论】:

  • 非常感谢!完美的解决方案! :D
猜你喜欢
  • 2011-05-14
  • 1970-01-01
  • 1970-01-01
  • 2012-11-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多