如何获取Windows当前的交互式用户会话数?

问题描述 投票:0回答:2

我正在编写一个Windows服务,需要知道机器中当前是否有任何用户登录。

到目前为止,我已经尝试过

Win32_LogonSession
(WMI) 和
LsaEnumerateLogonSessions
/
LsaGetLogonSessionData
(secure32.dll)。

两者都可以工作,并且似乎返回相同的数据,但是当用户注销时它们更新太慢:

  • 系统启动时,返回“0个交互用户”。 (好的)
  • 当我登录时,他们返回“1 个交互式用户”。 (好的)
  • 但是当我注销时,用户数保持为1。新登录后,用户数为2,依此类推。

因此 Win32_LogonSession 和 LsaEnumerateLogonSessions 都足够好。 服务需要在最后一个交互用户离开后 5 分钟内知道。

甚至 SysInternals 的 LogonSessions.exe 也没有给出最新答案。
另外,答案不能是“监视登录和注销事件并有一个计数器变量”,因为该服务可以随时启动。

windows winapi language-agnostic windows-services
2个回答
10
投票

我最终采用了以下方法:计算至少有一个进程正在运行的交互式会话的数量。

1) 获取每个交互式会话的登录会话 ID。

  • LsaEnumerateLogonSessions (secure32.dll)
  • LsaGetLogonSessionData (secure32.dll)
  • sessionData.LogonType = SECURITY_LOGON_TYPE.Interactive 或 sessionData.LogonType = SECURITY_LOGON_TYPE.RemoteInteractive
  • sessionData.LoginID <- Keep this value in a LUID set.
  • LsaFreeReturnBuffer (secure32.dll)

2) 获取每个正在运行的进程的登录会话 ID。

[首先我们需要为当前应用程序启用SeDebugPrivilege。]

  • 获取当前进程(kernel32.dll)
  • OpenProcessToken TOKEN_ADJUST_PRIVILEGES(advapi32.dll)
  • LookupPrivilegeValue SE_DEBUG_NAME(advapi32.dll)
  • 调整TokenPrivileges(advapi32.dll)
  • 关闭句柄(kernel32.dll)

【然后检索我们想要的数据。】

3)设置交集基数

interactiveSessionsCount = | { sessionData.LoginID } ∩ { accessTokenStatistics.AuthenticationId } |

Obs:sessionData.LoginID 和 accessTokenStatistics.AuthenticationId 都是 LUID 类型。


2
投票

WTSEnumerateSessionsA + WTSQuerySessionInformationA 可以更好地检测活动/交互式会话。

© www.soinside.com 2019 - 2024. All rights reserved.