"SERVICE_CONTROL_SESSIONCHANGE" Windows 10 中的 C++ 服务应用程序从未收到通知

"SERVICE_CONTROL_SESSIONCHANGE" notification is never received in C++ service application in Windows 10

我一直在尝试开发一个服务应用程序来连接 windows 的 login/logout 事件。我的开发环境是 Windows 10. 由于它是一个服务应用程序,根据 Whosebug 和其他开发平台中一些现有帖子的建议,我注册了该服务以在不同事件中得到通知。下面是我试过的片段。

SERVICE_STATUS_HANDLE   gSvcStatusHandle;

VOID WINAPI SvcCtrlHandlerEx(DWORD dwControl, DWORD dwEventType, LPVOID lpEventData, LPVOID lpContext)
{

    switch (dwControl)
    {
    case SERVICE_CONTROL_STOP:
        writeEventLog(utils.GetDefaultTitle(), L"Service About to end");
        ReportSvcStatus(SERVICE_STOP_PENDING, NO_ERROR, 0);

        // Signal the service to stop.

        SetEvent(ghSvcStopEvent);
        ReportSvcStatus(gSvcStatus.dwCurrentState, NO_ERROR, 0);

        applicationLogger.LogWarning("Service stopped.");
        break;
        return;

    case SERVICE_CONTROL_INTERROGATE:
        writeEventLog(GetDefaultTitle(), L"Service=interrogate");
        applicationLogger.LogWarning("Service Interrogate.");
        break;

    case SERVICE_CONTROL_PAUSE:
        writeEventLog(GetDefaultTitle(), L"Service=paused");
        applicationLogger.LogWarning("Service pasued.");
        break;

    case SERVICE_CONTROL_CONTINUE:
        writeEventLog(GetDefaultTitle(), L"Service=continued");
        applicationLogger.LogWarning("Service continued.");
        break;
    case SERVICE_CONTROL_SESSIONCHANGE:
        writeEventLog(GetDefaultTitle(), L"Service=Session=Changed");
        applicationLogger.LogWarning("Session changed");
    if (WTS_SESSION_LOGOFF == (dwEvtype & WTS_SESSION_LOGOFF))
        {
            WTSSESSION_NOTIFICATION* pSessionNotification = static_cast<WTSSESSION_NOTIFICATION*>(pEvtData);
        }
        else if (WTS_SESSION_LOGON == (dwEvtype & WTS_SESSION_LOGOFF))
        {
            WTSSESSION_NOTIFICATION* pSessionNotification = static_cast<WTSSESSION_NOTIFICATION*>(pEvtData);
        break;
        default:
        writeEventLog(GetDefaultTitle(), L"Service=Dfault");
        applicationLogger.LogWarning("Service default.");
        break;
    }
    
}

VOID WINAPI SvcMain(DWORD dwArgc, LPTSTR* lpszArgv)
{
    gSvcStatusHandle = RegisterServiceCtrlHandlerEx(SVCNAME, reinterpret_cast<LPHANDLER_FUNCTION_EX>(SvcCtrlHandlerEx), NULL);
}

出于调试目的,每当服务收到任何事件通知时,我都会尝试记录事件名称。但是,我收到的唯一通知是我尝试停止服务,“case SERVICE_CONTROL_STOP”将被执行。我有兴趣接收“SERVICE_CONTROL_SESSIONCHANGE”事件,以便我可以检索用户的登录信息。

所以,你能指出我做错的地方吗? “SERVICE_CONTROL_SESSIONCHANGE”中的方法也是从 windows 获取 login/logout 事件的正确方法吗? 我尝试在 windows10 系统中登录和注销,但事件查看器中没有写入日志。

要在 HandlerEx 回调中接收 SERVICE_CONTROL_SESSIONCHANGE 通知,您需要调用 SetServiceStatus() 并在 SERVICE_STATUS::dwControlsAccepted 字段中启用 SERVICE_ACCEPT_SESSIONCHANGE 标志。

Control code Meaning
SERVICE_ACCEPT_SESSIONCHANGE 0x00000080 The service is notified when the computer's session status has changed. This enables the system to send SERVICE_CONTROL_SESSIONCHANGE notifications to the service.

至于您的处理程序本身,您不应将 operator&dwEventType 参数一起使用,因为它不是位掩码。使用 operator== 代替(或 switch):

case SERVICE_CONTROL_SESSIONCHANGE:
    writeEventLog(GetDefaultTitle(), L"Service=Session=Changed");
    applicationLogger.LogWarning("Session changed");
    if (dwEventType == WTS_SESSION_LOGOFF)
    {
        WTSSESSION_NOTIFICATION* pSessionNotification = static_cast<WTSSESSION_NOTIFICATION*>(lpEventData);
        // ...
    }
    else if (dwEventType == WTS_SESSION_LOGON)
    {
        WTSSESSION_NOTIFICATION* pSessionNotification = static_cast<WTSSESSION_NOTIFICATION*>(lpEventData);
        // ...
    }
    break;