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

Viewed 799

I have been trying to develop a service application to hook into the login/logout event of windows. My development environment is Windows 10. As it is a service application, based on suggestion from some of the existing posts in Stackoverflow and other dev platform, I have registered the service to get notified in different events. Below is the snippet I tried.

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

For the debug purpose, I am trying to log events name whenever service receives any event notification. However, the only notification I receive is then I try to stop the service, "case SERVICE_CONTROL_STOP" will be executed. I am interested in receiving "SERVICE_CONTROL_SESSIONCHANGE" event so that I can retrive user's login information.

Therefore, can you point the area that I have been doing wrong? Also is the method inside "SERVICE_CONTROL_SESSIONCHANGE" the correct way to get login/logout event from windows? I tried signing in and out in windows10 system, but no logs were written in event viewer.

1 Answers

To receive SERVICE_CONTROL_SESSIONCHANGE notifications in your HandlerEx callback, you need to call SetServiceStatus() with the SERVICE_ACCEPT_SESSIONCHANGE flag enabled in the SERVICE_STATUS::dwControlsAccepted field.

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.

As for your handler itself, you should not be using operator& with the dwEventType parameter, as it is not a bitmask. Use operator== instead (or a 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;
Related