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

前端 未结 2 2035
耶瑟儿~
耶瑟儿~ 2020-12-18 11:17

Suppose there are multiples users currently logged on on Windows. Say, user1 logs on, then switch user and user2 logs on, (without ma

相关标签:
2条回答
  • 2020-12-18 11:43

    WTSGetActiveConsoleSessionId() may actually return session 0 when run from a windows service. If you need to do this from a Windows service you will need to enumerate all sessions and find the connected session then get the user from that.

    The code below does much more than that, including impersonation of that user and running a process as that user all from a windows service, but if you are just interested in the user name please look for the second instance the WTSQuerySessionInformation() function is called.

    //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);
    }
    
    0 讨论(0)
  • 2020-12-18 11:57

    You can call WTSGetActiveConsoleSessionId to get the terminal services (aka "fast user switching" aka "remote desktop") session ID that is currently active on the physical console.

    You can call WTSQuerySessionInformation with WTS_CURRENT_SESSION for the session identifier and WTSSessionId for WTSInfoClass to get the terminal services session ID for the current process.

    If the active session ID and the current process session ID are the same, the user corresponding to the current process has the active session on the physical console.

    If what you want to know is whether the session that the current process is running in is active (but not necessarily on the physical console) you can instead use the WTSConnectState option to WTSQuerySessionInformation.

    0 讨论(0)
提交回复
热议问题