I'm writing a Windows service that needs to know whether there are any users currently logged-on in the machine.
So far I've tried Win32_LogonSession
(WMI), and LsaEnumerateLogonSessions
/LsaGetLogonSessionData
(secur32.dll).
Both work, and seem to return the same data, but they are too slow to update when a user log off:
- When the system starts, they return "0 interactive users". (OK)
- When I log on, they return "1 interactive user". (OK)
- But then when I log off, the number of users is kept at 1. After a new log-on, the number is 2, and so on.
Thus Win32_LogonSession nor LsaEnumerateLogonSessions are good enough. The service needs to know within 5 minutes after the last interactive user leaves.
Not even SysInternals' LogonSessions.exe gives up-to-date answers.
Also, the answer cannot be "monitor logon and logoff events and have a counter variable", because the service can be started at any time.
I ended up with the following approach: count the number of interactive sessions which have at least one process running.
1) Get the logon session id for each interactive session.
- LsaEnumerateLogonSessions (secur32.dll)
- LsaGetLogonSessionData (secur32.dll)
- sessionData.LogonType = SECURITY_LOGON_TYPE.Interactive or sessionData.LogonType = SECURITY_LOGON_TYPE.RemoteInteractive
- sessionData.LoginID <- Keep this value in a LUID set.
- LsaFreeReturnBuffer (secur32.dll)
2) Get the logon session id for each running process.
[First we need to enable the SeDebugPrivilege to the current application.]
- GetCurrentProcess (kernel32.dll)
- OpenProcessToken TOKEN_ADJUST_PRIVILEGES (advapi32.dll)
- LookupPrivilegeValue SE_DEBUG_NAME (advapi32.dll)
- AdjustTokenPrivileges (advapi32.dll)
- CloseHandle (kernel32.dll)
[Then retrieve the data we want.]
- EnumProcesses (psapi.dll)
- OpenProcess PROCESS_QUERY_INFORMATION (kernel32.dll)
- OpenProcessToken TOKEN_QUERY (advapi32.dll)
- GetTokenInformation TOKEN_INFORMATION_CLASS.TokenStatistics (advapi32.dll)
- accessTokenStatistics.AuthenticationId <- Keep this value in a LUID set.
- CloseHandle (kernel32.dll)
3) Sets intersection cardinality
interactiveSessionsCount = | { sessionData.LoginID } ∩ { accessTokenStatistics.AuthenticationId } |
Obs: sessionData.LoginID and accessTokenStatistics.AuthenticationId are both of type LUID.
来源:https://stackoverflow.com/questions/6255424/how-to-get-the-current-number-of-interactive-user-sessions-in-windows