如何在多个用户登录Windows时获取活动用户
How to get the active user when multiple users are logged on in Windows?
假设有多个用户当前登录Windows。假设,user1
登录,然后switch user
和user2
登录,(不使user1
注销)。假设有一个应用程序在用户登录时运行。有两个用户user1
和user2
登录,其中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);
}
- 是否有 Windows 用户空间函数来枚举连接的网络共享?
- Windows 后台服务(系统配置文件)无法使用 C++ 访问 win 10 上的用户 appData 文件夹?
- 通过JNA发送用户定义的Windows消息
- 当PSO细粒度策略对使用AdsGetObject MSDN API的Windows操作系统生效时,如何获取用户密码到期日
- 在Windows中将用户输入屏蔽为星号
- 检查用户是否是 Windows 中本地计算机上的管理员C++
- 如何通过Windows API获取所有(未禁用)用户SID?
- 如何从 Windows 上的服务在未登录用户的桌面上启动应用程序
- 将Windows SYSTEMTIME转换为字符串或字符buf,C++与用户的"Region and Language"格式?
- 从Windows上的系统工作的服务中获取用户文档文件夹.C++
- 获取 Windows 系统已加入 Azure AD 时登录用户的 UserPrincipalName
- 从 Windows KMD 调用用户空间 API 函数
- 标准Windows 7用户如何能够删除C:Program Files下的文件
- 如何在Windows控制台中禁用用户选择
- 仅通过帐户名来获取Windows用户帐户SID
- 如何检查用户登录到Windows的时间
- Windows:如何获取完整用户帐户
- 有任何替代SHGetKnownFolderPath的Windows XP用户令牌的方案吗
- 以系统用户 (Windows) 身份调用应用程序
- 如何创建桌面图标/按钮来启动用户Windows屏幕保护程序,并设置选项