简体   繁体   English

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

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

Suppose there are multiples users currently logged on on Windows. 假设有多个用户当前在Windows上登录。 Say, user1 logs on, then switch user and user2 logs on, (without making user1 log off). 说, user1登录,然后switch useruser2的日志上,(未做user1注销)。 Suppose there is an app which runs when user logs on. 假设有一个应用程序在用户登录时运行。 There are two users user1 and user2 logged on, with user2 as the active user, and there are two apps. 有两个用户user1user2登录, user2作为活动用户,并且有两个应用程序。

My question is: How does the app know whether its corresponding user is active or not? 我的问题是:应用程序如何知道其相应的用户是否处于活动状态? Ie, app in user2 domain determines that its user is active, while app in user1 domain determines its user is currently inactive. 即, user2域中的app确定其用户处于活动状态,而user1域中的app确定其用户当前处于非活动状态。 Thanks! 谢谢!

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. 您可以调用WTSGetActiveConsoleSessionId来获取当前在物理控制台上处于活动状态的终端服务(也称为“快速用户切换”,也称为“远程桌面”)会话ID。

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. 你可以调用WTSQuerySessionInformationWTS_CURRENT_SESSION的会话标识符和WTSSessionIdWTSInfoClass获得终端服务会话ID当前进程。

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. 如果活动会话ID和当前进程会话ID相同,则与当前进程对应的用户在物理控制台上具有活动会话。

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 . 如果您想知道的是当前进程正在运行的会话是否处于活动状态(但不一定在物理控制台上),则可以使用WTSConnectState选项来使用WTSQuerySessionInformation

WTSGetActiveConsoleSessionId() may actually return session 0 when run from a windows service. 从Windows服务运行时,WTSGetActiveConsoleSessionId()实际上可能返回会话0。 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. 如果您需要从Windows服务执行此操作,则需要枚举所有会话并找到已连接的会话,然后从中获取用户。

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. 下面的代码远不止这些,包括模拟该用户并从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);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM