在服务中感知用户登录

前言

今天和同事聊起感知用户登录的方法. 想起以前做过一个<<在服务中以当前用户身份启动一个程序>>的试验, 里面有当不同用户身份登录(在服务程序中轮询时, 得到不一样的SessionID)时, 会以当前用户身份启动一个示例程序.这就已经感知了不同用户登录.

回家做了一个试验, 验证不同用户登录时, 收集用户登录的信息, 只是做验证(记录当前用户登录的用户名, 其他用户信息没取(可以取到更多的信息)).

Demo下载点

DetectUserLogin.zip
有些函数在vc6里没有,改起来需要花更多时间, 就用vs2013做了一个工程.

关键API

WTSEnumerateSessions
WTSQuerySessionInformation
WTSFreeMemory

程序片段

试验结果

[09588] 2017-02-23 00:09:51 << CProcessStarter::FindActiveSessionId(), bFindActiveSession = [TRUE], dwSessionId = 1
[09588] 2017-02-23 00:09:51 m_strSessionInfo = LostSpeed


[09588] 2017-02-23 00:09:53 >> CProcessStarter::FindActiveSessionId()
[09588] 2017-02-23 00:09:53 << CProcessStarter::FindActiveSessionId(), bFindActiveSession = [TRUE], dwSessionId = 1
[09588] 2017-02-23 00:12:43 m_strSessionInfo = stdUser1


[09588] 2017-02-23 00:12:46 >> CProcessStarter::FindActiveSessionId()
[09588] 2017-02-23 00:12:46 << CProcessStarter::FindActiveSessionId(), bFindActiveSession = [TRUE], dwSessionId = 2
[09588] 2017-02-23 00:13:48 m_strSessionInfo = stduser2


[09588] 2017-02-23 00:13:51 >> CProcessStarter::FindActiveSessionId()
[09588] 2017-02-23 00:13:51 << CProcessStarter::FindActiveSessionId(), bFindActiveSession = [TRUE], dwSessionId = 3
[09588] 2017-02-23 00:14:30 m_strSessionInfo = LostSpeed

服务程序

// @file LsServcie.cpp
// @brief 在服务中感知用户登录

#include "stdafx.h"
#include <windows.h>
#include "ThreadManager.h"
#include "UtilityHelper.h"
#include "SCM.h"
#include "ProcessStarter.h"

#define SERVICE_NAME_W L"ls_test_service"
#define SERVICE_VER_W L"1, 0, 0, 2"
#define PROJECT_MODIFY_TIME L"2017-0222-1959"

#define LOG_FILE_NAME_DLG_NOTIFY L"log_dlg_notify.txt"
#define LOG_FILE_NAME_LSSERVICEFORTEST L"log_lsServiceForTest.txt"

#define FILE_NAME_NOTIFY _T("notepad.exe")
// X64下的notepad.exe的原始名称为NOTEPAD.EXE.MUI
#define FILE_ORGNAME_NOTIFY _T("NOTEPAD.EXE.MUI")

VOID WINAPI ServiceMain(DWORD dwArgc, LPWSTR* lpszArgv);
SERVICE_TABLE_ENTRYW lpServiceStartTable[] = {
    { SERVICE_NAME_W, ServiceMain },
    { NULL, NULL }
};

SERVICE_STATUS_HANDLE g_hServiceCtrlHandler = NULL;
SERVICE_STATUS g_ServiceStatus;
std::wstring g_strPathNameMe = L"";
std::wstring g_strCmdLine = L"";
ns_base::CThreadManager g_ThreadManager;

VOID ServiceMainProc();
static UINT WINAPI ThreadProcWorker(void* pParam);
BOOL ThreadProcStart_Worker();
BOOL ThreadProcStop_Worker();

VOID ExecuteAsService();
VOID WINAPI ServiceHandler(DWORD fdwControl);

std::wstring GetLogPathName_lsServiceForTest();

int APIENTRY _tWinMain(HINSTANCE hInstance,
                       HINSTANCE hPrevInstance,
                       LPTSTR    lpCmdLine,
                       int       nCmdShow)
{
    std::wstring strLogFilePathName = L"";
    ns_base::GetFilePathName_Me(g_strPathNameMe);
    g_strCmdLine = (NULL != lpCmdLine) ? lpCmdLine : L"";
    strLogFilePathName = GetLogPathName_lsServiceForTest().c_str();
    SetLogFilePathName(strLogFilePathName.c_str());
    ServiceMainProc();
    return 0;
}

VOID ServiceMainProc()
{
    WriteLogEx(L">> ServiceMainProc() [%s][%s][%s]", SERVICE_NAME_W, SERVICE_VER_W, PROJECT_MODIFY_TIME);

    if (ns_base::StringCompare_equ(g_strCmdLine.c_str(), L"-i")
            || ns_base::StringCompare_equ(g_strCmdLine.c_str(), L"-I")) {
        ns_base::ServiceInstall(g_strPathNameMe.c_str(), SERVICE_NAME_W);
    } else if (ns_base::StringCompare_equ(g_strCmdLine.c_str(), L"-s")
               || ns_base::StringCompare_equ(g_strCmdLine.c_str(), L"-S")) {
        ns_base::ServiceStart(SERVICE_NAME_W);
    } else if (ns_base::StringCompare_equ(g_strCmdLine.c_str(), L"-k")
               || ns_base::StringCompare_equ(g_strCmdLine.c_str(), L"-K")) {
        ns_base::ServiceStop(SERVICE_NAME_W);
    } else if (ns_base::StringCompare_equ(g_strCmdLine.c_str(), L"-u")
               || ns_base::StringCompare_equ(g_strCmdLine.c_str(), L"-U")) {
        ns_base::ServiceUnInstall(SERVICE_NAME_W);
    } else {
        ExecuteAsService();
    }

    //  #ifdef _DEBUG
    //  // 要调试线程时, 这里要等着, 要不主线程退出时, 子线程也结束了
    //      while(1) {
    //          Sleep(10);
    //      }
    //  #endif
    WriteLogEx(L"<< ServiceMainProc() [%s][%s][%s]", SERVICE_NAME_W, SERVICE_VER_W, PROJECT_MODIFY_TIME);
}

VOID ExecuteAsService()
{
    WriteLogEx(L">> ExecuteAsService");

    if (!ThreadProcStart_Worker()) {
        WriteLogEx(L"ThreadProcStart_Worker failed[%d]", GetLastError());
    }

    if (!StartServiceCtrlDispatcherW(lpServiceStartTable)) {
        WriteLogEx(L"StartServiceCtrlDispatcher failed[%d]", GetLastError());
    }

    WriteLogEx(L"<< ExecuteAsService");
}

VOID WINAPI ServiceMain(DWORD dwArgc, LPWSTR* lpszArgv)
{
    WriteLogEx(L">> ServiceMain(%d, lpszArgv)", dwArgc);

    do {
        g_ServiceStatus.dwServiceType = SERVICE_WIN32;
        g_ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
        g_ServiceStatus.dwControlsAccepted =
            SERVICE_ACCEPT_STOP
            | SERVICE_ACCEPT_PAUSE_CONTINUE
            | SERVICE_ACCEPT_SHUTDOWN
            | SERVICE_ACCEPT_PARAMCHANGE
            | SERVICE_ACCEPT_NETBINDCHANGE
            | SERVICE_ACCEPT_HARDWAREPROFILECHANGE
            | SERVICE_ACCEPT_POWEREVENT
            | SERVICE_ACCEPT_SESSIONCHANGE
            | SERVICE_ACCEPT_PRESHUTDOWN
            | SERVICE_ACCEPT_TIMECHANGE
            | SERVICE_ACCEPT_TRIGGEREVENT;
        g_ServiceStatus.dwWin32ExitCode = 0;
        g_ServiceStatus.dwServiceSpecificExitCode = 0;
        g_ServiceStatus.dwCheckPoint = 0;
        g_ServiceStatus.dwWaitHint = 0;
        g_hServiceCtrlHandler = RegisterServiceCtrlHandlerW(SERVICE_NAME_W, ServiceHandler);

        if (NULL == g_hServiceCtrlHandler) {
            ns_base::NotifyFailed_RegisterServiceCtrlHandler(GetLastError(), SERVICE_NAME_W);
            break;
        }

        // Initialization complete - report running status
        g_ServiceStatus.dwCurrentState = SERVICE_RUNNING;
        g_ServiceStatus.dwCheckPoint = 0;
        g_ServiceStatus.dwWaitHint = 0;

        if (!SetServiceStatus(g_hServiceCtrlHandler, &g_ServiceStatus)) {
            ns_base::NotifyFailed_SetServiceStatus(GetLastError(), SERVICE_NAME_W);
        }
    } while (0);

    WriteLogEx(L"<< ServiceMain(%d, lpszArgv)", dwArgc);
}

VOID WINAPI ServiceHandler(DWORD fdwControl)
{
    int iIndex = 0;
    WriteLogEx(L">> ServiceHandler(%d)", fdwControl);

    switch (fdwControl) {
        case SERVICE_CONTROL_STOP:
        case SERVICE_CONTROL_SHUTDOWN:
            g_ThreadManager.StopThread(TRUE, L"g_ThreadManager");
            g_ServiceStatus.dwWin32ExitCode = 0;
            g_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
            g_ServiceStatus.dwCheckPoint = 0;
            g_ServiceStatus.dwWaitHint = 0;
            break;
        case SERVICE_CONTROL_PAUSE:
            g_ServiceStatus.dwCurrentState = SERVICE_PAUSED;
            break;
        case SERVICE_CONTROL_CONTINUE:
            g_ServiceStatus.dwCurrentState = SERVICE_RUNNING;
            break;
        default:
            WriteLogEx(L"Unrecognized opcode %d\n", fdwControl);
    };

    if (!SetServiceStatus(g_hServiceCtrlHandler, &g_ServiceStatus)) {
        ns_base::NotifyFailed_SetServiceStatus(GetLastError(), SERVICE_NAME_W);
    }

    WriteLogEx(L"<< ServiceHandler(%d)", fdwControl);
}

static UINT WINAPI ThreadProcWorker(void* pParam)
{
    BOOL bFirstRun = TRUE; // 标记-首次运行
    BOOL bLog = TRUE;
    DWORD dwSessionIdPrev = -1;
    DWORD dwSessionId = -1;
    size_t nSleepTotal = 0;
    UINT uRc = S_FALSE;
    std::wstring strObjPathName = L"";
    std::wstring strOrgObjPathName = L"";
    std::wstring strCmdLine = L"";
    std::wstring strCmdLineAll = L"";
    ns_base::TAG_THREAD_MANAGER_PARAM ThreadManagerParam;
    ns_base::TAG_THREAD_MANAGER_PARAM* pThreadManagerParam = NULL;
    CProcessStarter ProcessStarter;
    WriteLogEx(L">> lsServiceForTest ThreadProcWorker");

    do {
        if (NULL == pParam) {
            break;
        }

        pThreadManagerParam = (ns_base::TAG_THREAD_MANAGER_PARAM*)pParam;
        ThreadManagerParam.copy((ns_base::TAG_THREAD_MANAGER_PARAM*)pParam);
        SAFE_DELETE(pThreadManagerParam);

        if (NULL == ThreadManagerParam.pThreadManager) {
            break;
        }

        while (!ThreadManagerParam.pThreadManager->IsNeedQuitThread()) {
            if (bFirstRun) {
                bFirstRun = FALSE;
            } else {
                if (!ns_base::SleepContinueEx(2000, 100, nSleepTotal)) {
                    continue;
                }
            }

            /// 保证 只有在SessionId变化的时候, 才打印 FindActiveSessionId 的日志
            if (!ProcessStarter.FindActiveSessionId(dwSessionId, bLog)
                    || (dwSessionIdPrev == dwSessionId)) {
                if (bLog) {
                    bLog = FALSE;
                }

                continue;
            }

            if (!bLog) {
                bLog = TRUE;
            }

            dwSessionIdPrev = dwSessionId;
            // 只是演示, 验证可以在服务中, 经过轮询, 得知SessionID的变化(不同用户登录的SessionID不同)
            // 由SessionID可以得到登录的用户名和其他登录信息
            // 通过记录日志, 来演示不同用户登录时, 可以在服务中感知到.
            WriteLogEx(_T("m_strSessionInfo = %s\r\n"), ProcessStarter.GetSessionInfo());
            continue;
        }

        uRc = S_OK;
    } while (0);

    WriteLogEx(L"<< FzAppService ThreadProcWorker");
    return uRc;
}

BOOL ThreadProcStart_Worker()
{
    BOOL bRc = FALSE;
    ns_base::TAG_THREAD_MANAGER_PARAM* pThreadManagerParam = NULL;

    if (!g_ThreadManager.IsNeedQuitThread()
            && !g_ThreadManager.IsThreadRunning()) {
        do {
            pThreadManagerParam = new ns_base::TAG_THREAD_MANAGER_PARAM;

            if (NULL == pThreadManagerParam) {
                break;
            }

            pThreadManagerParam->pThreadManager = &g_ThreadManager;
            g_ThreadManager.SetThreadHandle(
                (HANDLE)_beginthreadex(
                    NULL,
                    0,
                    &ThreadProcWorker,
                    (void*)pThreadManagerParam,
                    0,
                    NULL));
            bRc = TRUE;
        } while (0);
    }

    return bRc;
}

BOOL ThreadProcStop_Worker()
{
    g_ThreadManager.StopThread(TRUE, L"g_ThreadManager");
    return TRUE;
}

std::wstring GetLogPathName_lsServiceForTest()
{
    std::wstring strPathName = L"";
    ns_base::GetPathName_Me(strPathName);
    strPathName += LOG_FILE_NAME_LSSERVICEFORTEST;
    return strPathName;
}

取登录信息的工具类

#ifndef _PROCESS_STARTER_H_
#define _PROCESS_STARTER_H_

#include "stdafx.h"

class CProcessStarter
{
    public:
        CProcessStarter();

        /// 如果没有找到"已经激活的SessionId", 说明还没有进入桌面
        BOOL FindActiveSessionId(OUT DWORD& dwSessionId, BOOL bNeedLog);
        BOOL Run(LPCWSTR pcProcessPathName, LPCWSTR pcCmdLine);
        const TCHAR* GetSessionInfo() {
            return m_strSessionInfo.c_str();
        }

    private:
        HANDLE GetCurrentUserToken();

    private:
        std::wstring m_strProcessPathName;
        std::wstring m_strCmdLine;
        std::wstring m_strSessionInfo;
};

#endif //_PROCESS_STARTER_H_

#include "stdafx.h"
#include "ProcessStarter.h"

#include <userenv.h>
#pragma comment(lib, "Userenv.lib")

#include <wtsapi32.h>
#pragma comment(lib, "Wtsapi32.lib")

CProcessStarter::CProcessStarter()
    : m_strProcessPathName(_T("")),
      m_strCmdLine(_T("")),
      m_strSessionInfo(_T(""))
{
}

BOOL CProcessStarter::FindActiveSessionId(OUT DWORD& dwSessionId, BOOL bNeedLog)
{
    BOOL bFindActiveSession = FALSE;
    DWORD dwIndex = 0;
    PWTS_SESSION_INFO pWtsSessionInfo = NULL;
    DWORD dwCntWtsSessionInfo = 0;
    LPTSTR pBuffer = NULL;
    DWORD dwRc = 0;

    if (bNeedLog) {
        WriteLogEx(L">> CProcessStarter::FindActiveSessionId()");
    }

    m_strSessionInfo = _T("");

    do {
        dwSessionId = (DWORD)(-1);

        if ((!WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, &pWtsSessionInfo, &dwCntWtsSessionInfo))
                || (NULL == pWtsSessionInfo)) {
            if (bNeedLog) {
                WriteLogEx(L"break 0 CProcessStarter::FindActiveSessionId()");
            }

            break;
        }

        for (dwIndex = 0; dwIndex < dwCntWtsSessionInfo; dwIndex++) {
            if (WTSActive == pWtsSessionInfo[dwIndex].State) {
                dwSessionId = pWtsSessionInfo[dwIndex].SessionId;
                bFindActiveSession = TRUE;

                if (WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE,
                                               dwSessionId,
                                               WTSUserName,
                                               &pBuffer, &dwRc)) {
                    if (NULL != pBuffer) {
                        m_strSessionInfo += (LPTSTR)pBuffer;
                        m_strSessionInfo += _T("\r\n");
                    }
                }

                if (NULL != pBuffer) {
                    WTSFreeMemory(pBuffer);
                }

                break;
            }
        }

        WTSFreeMemory(pWtsSessionInfo);

        if (!bFindActiveSession) {
            if (bNeedLog) {
                WriteLogEx(L"break 1 CProcessStarter::FindActiveSessionId()");
            }

            break;
        }
    } while (0);

    if (bNeedLog) {
        WriteLogEx(L"<< CProcessStarter::FindActiveSessionId(), bFindActiveSession = [%s], dwSessionId = %d",
                   bFindActiveSession ? L"TRUE" : L"FALSE",
                   dwSessionId);
    }

    return bFindActiveSession;
}

HANDLE CProcessStarter::GetCurrentUserToken()
{
    DWORD dwSessionId = 0;
    HANDLE hCurrentToken = NULL;
    HANDLE hPrimaryToken = NULL;
    WriteLogEx(L">> CProcessStarter::GetCurrentUserToken()");

    do {
        if (!FindActiveSessionId(dwSessionId, TRUE)) {
            WriteLogEx(L"break 0 CProcessStarter::GetCurrentUserToken()");
            break;
        }

        if (!WTSQueryUserToken(dwSessionId, &hCurrentToken)
                || (NULL == hCurrentToken)) {
            WriteLogEx(L"break 2 CProcessStarter::GetCurrentUserToken()");
            break;
        }

        if (!DuplicateTokenEx(hCurrentToken, TOKEN_ASSIGN_PRIMARY | TOKEN_ALL_ACCESS, 0, SecurityImpersonation, TokenPrimary, &hPrimaryToken)) {
            WriteLogEx(L"break 3 CProcessStarter::GetCurrentUserToken()");
            break;
        }
    } while (0);

    WriteLogEx(L"<< CProcessStarter::GetCurrentUserToken(), hCurrentToken = 0x%p, hPrimaryToken = 0x%p",
               hCurrentToken,
               hPrimaryToken);
    SAFE_CLOSE_HANDLE(hCurrentToken);
    return hPrimaryToken;
}

BOOL CProcessStarter::Run(LPCWSTR pcProcessPathName, LPCWSTR pcCmdLine)
{
    BOOL bRc = FALSE;
    BOOL bTmp = FALSE;
    HANDLE hPrimaryToken = NULL;
    STARTUPINFOA StartupInfo = {0};
    PROCESS_INFORMATION processInfo = {0};
    std::wstring command = L"";
    LPVOID lpEnvironment = NULL;
    WriteLogEx(L">> CProcessStarter::Run");

    do {
        if ((NULL == pcProcessPathName) /*|| (!ns_base::IsFileExist(pcProcessPathName))*/) {
            WriteLogEx(L"break 0 CProcessStarter::Run");
            break;
        }

        this->m_strProcessPathName = pcProcessPathName;
        this->m_strCmdLine = (NULL != pcCmdLine) ? pcCmdLine : L"";
        hPrimaryToken = GetCurrentUserToken();

        if (NULL == hPrimaryToken) {
            WriteLogEx(L"break 1 CProcessStarter::Run");
            break;
        }

        StartupInfo.cb = sizeof(STARTUPINFO);
        command = L"\"";
        command += m_strProcessPathName.c_str();
        command += L"\"";

        if (m_strCmdLine.length() != 0) {
            command += L" ";
            command += m_strCmdLine.c_str();
        }

        WriteLogEx(L"command = [%s]", command.c_str());

        if (!CreateEnvironmentBlock(&lpEnvironment, hPrimaryToken, TRUE)) {
            WriteLogEx(L"!CreateEnvironmentBlock by hPrimaryToken");
        }

        bTmp = CreateProcessAsUserA(
                   hPrimaryToken,
                   0,
                   (LPSTR)ns_base::W2Aex(command.c_str()).c_str(),
                   NULL,
                   NULL,
                   FALSE,
                   NORMAL_PRIORITY_CLASS | CREATE_UNICODE_ENVIRONMENT,
                   lpEnvironment, // __in_opt    LPVOID lpEnvironment,
                   0,
                   &StartupInfo,
                   &processInfo);

        if (NULL != lpEnvironment) {
            DestroyEnvironmentBlock(lpEnvironment);
        }

        WriteLogEx(L"CreateProcessAsUserA = %s", bTmp ? L"TRUE" : L"FALSE");

        if (!bTmp) {
            break;
        }

        bRc = TRUE;
    } while (0);

    SAFE_CLOSE_HANDLE(hPrimaryToken);
    WriteLogEx(L"<< CProcessStarter::Run, bRc = [%s]", bRc ? L"TRUE" : L"FALSE");
    return bRc;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值