如何在多个用户登录Windows时获取活动用户

How to get the active user when multiple users are logged on in Windows?

本文关键字:用户 Windows 获取 活动 登录      更新时间:2023-10-16

假设有多个用户当前登录Windows。假设,user1登录,然后switch useruser2登录,(不使user1注销)。假设有一个应用程序在用户登录时运行。有两个用户user1user2登录,其中user2为活跃用户,并且有两个应用程序。

我的问题是:应用程序如何知道其对应的用户是否活跃?即,user2域的app确定其用户为活动状态,而user1域的app确定其用户当前为非活动状态。谢谢!

您可以调用WTSGetActiveConsoleSessionId来获取当前在物理控制台上活动的终端服务(又名"快速用户切换"又名"远程桌面")会话ID。

可以用WTS_CURRENT_SESSION调用WTSQuerySessionInformation作为会话标识符,用WTSSessionId调用WTSInfoClass来获取当前进程的终端服务会话ID。

如果激活的会话ID和当前进程的会话ID相同,则当前进程对应的用户在物理控制台中有激活的会话。

如果您想知道当前进程正在其中运行的会话是否活动(但不一定在物理控制台上),您可以使用WTSConnectState选项来代替WTSQuerySessionInformation

WTSGetActiveConsoleSessionId()从windows服务运行时实际上可能返回会话0。如果您需要从Windows服务中执行此操作,则需要枚举所有会话并找到连接的会话,然后从中获取用户。

下面的代码所做的远远不止这些,包括模拟该用户并作为该用户从windows服务运行进程,但是如果您只对用户名感兴趣,请查找调用WTSQuerySessionInformation()函数的第二个实例。

//Function to run a process as active user from windows service
void ImpersonateActiveUserAndRun(WCHAR* path, WCHAR* args)
{
    DWORD session_id = -1;
    DWORD session_count = 0;
    WTS_SESSION_INFOA *pSession = NULL;

    if (WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, &pSession, &session_count))
    {
        //log success
    }
    else
    {
        //log error
        return;
    }
    for (int i = 0; i < session_count; i++)
    {
        session_id = pSession[i].SessionId;
        WTS_CONNECTSTATE_CLASS wts_connect_state = WTSDisconnected;
        WTS_CONNECTSTATE_CLASS* ptr_wts_connect_state = NULL;
        DWORD bytes_returned = 0;
        if (::WTSQuerySessionInformation(
            WTS_CURRENT_SERVER_HANDLE,
            session_id,
            WTSConnectState,
            reinterpret_cast<LPTSTR*>(&ptr_wts_connect_state),
            &bytes_returned))
        {
            wts_connect_state = *ptr_wts_connect_state;
            ::WTSFreeMemory(ptr_wts_connect_state);
            if (wts_connect_state != WTSActive) continue;
        }
        else
        {
            //log error
            continue;
        }
        HANDLE hImpersonationToken;
        if (!WTSQueryUserToken(session_id, &hImpersonationToken))
        {
            //log error
            continue;
        }

        //Get real token from impersonation token
        DWORD neededSize1 = 0;
        HANDLE *realToken = new HANDLE;
        if (GetTokenInformation(hImpersonationToken, (::TOKEN_INFORMATION_CLASS) TokenLinkedToken, realToken, sizeof(HANDLE), &neededSize1))
        {
            CloseHandle(hImpersonationToken);
            hImpersonationToken = *realToken;
        }
        else
        {
            //log error
            continue;
        }

        HANDLE hUserToken;
        if (!DuplicateTokenEx(hImpersonationToken,
            //0,
            //MAXIMUM_ALLOWED,
            TOKEN_ASSIGN_PRIMARY | TOKEN_ALL_ACCESS | MAXIMUM_ALLOWED,
            NULL,
            SecurityImpersonation,
            TokenPrimary,
            &hUserToken))
        {
            //log error
            continue;
        }
        // Get user name of this process
        //LPTSTR pUserName = NULL;
        WCHAR* pUserName;
        DWORD user_name_len = 0;
        if (WTSQuerySessionInformationW(WTS_CURRENT_SERVER_HANDLE, session_id, WTSUserName, &pUserName, &user_name_len))
        {
            //log username contained in pUserName WCHAR string
        }
        //Free memory                         
        if (pUserName) WTSFreeMemory(pUserName);
        ImpersonateLoggedOnUser(hUserToken);
        STARTUPINFOW StartupInfo;
        GetStartupInfoW(&StartupInfo);
        StartupInfo.cb = sizeof(STARTUPINFOW);
        //StartupInfo.lpDesktop = "winsta0\default";
        PROCESS_INFORMATION processInfo;
        SECURITY_ATTRIBUTES Security1;
        Security1.nLength = sizeof SECURITY_ATTRIBUTES;
        SECURITY_ATTRIBUTES Security2;
        Security2.nLength = sizeof SECURITY_ATTRIBUTES;
        void* lpEnvironment = NULL;
        // Get all necessary environment variables of logged in user
        // to pass them to the new process
        BOOL resultEnv = CreateEnvironmentBlock(&lpEnvironment, hUserToken, FALSE);
        if (!resultEnv)
        {
            //log error
            continue;
        }
        WCHAR PP[1024]; //path and parameters
        ZeroMemory(PP, 1024 * sizeof WCHAR);
        wcscpy(PP, path);
        wcscat(PP, L" ");
        wcscat(PP, args);
        // Start the process on behalf of the current user 
        BOOL result = CreateProcessAsUserW(hUserToken, 
            NULL,
            PP,
            //&Security1,
            //&Security2,
            NULL,
            NULL,
            FALSE, 
            NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE,
            //lpEnvironment,
            NULL,
            //"C:\ProgramData\some_dir",
            NULL,
            &StartupInfo,
            &processInfo);
        if (!result)
        {
            //log error
        }
        else
        {
            //log success
        }
        DestroyEnvironmentBlock(lpEnvironment);
        CloseHandle(hImpersonationToken);
        CloseHandle(hUserToken);
        CloseHandle(realToken);
        RevertToSelf();
    }
    WTSFreeMemory(pSession);
}