我正在开发一项服务,该服务需要检测登录到单台计算机的所有用户的用户状态。具体来说,我想检查屏幕保护程序是否处于活动状态以及会话是否被锁定。
此代码将在系统级服务下运行,并且没有可见的UI,因此可以排除多个选项(捕获WM消息等)。
除了正常的工作站之外,我还希望能够在有多个用户登录的终端服务器上工作。由于这些要求,我想知道是否需要涉及多个Win32 API。
关于从哪里开始的任何想法?
答案 0 :(得分:19)
作为服务,您可以使用事件OnSessionChange来捕捉所有相关时刻。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceProcess;
using System.Diagnostics;
namespace MyCode
{
class MyService : ServiceBase
{
public MyService()
{
this.CanHandleSessionChangeEvent = true;
}
protected override void OnSessionChange(SessionChangeDescription changeDescription)
{
switch (changeDescription.Reason)
{
case SessionChangeReason.SessionLogon:
Debug.WriteLine(changeDescription.SessionId + " logon");
break;
case SessionChangeReason.SessionLogoff:
Debug.WriteLine(changeDescription.SessionId + " logoff");
break;
case SessionChangeReason.SessionLock:
Debug.WriteLine(changeDescription.SessionId + " lock");
break;
case SessionChangeReason.SessionUnlock:
Debug.WriteLine(changeDescription.SessionId + " unlock");
break;
}
base.OnSessionChange(changeDescription);
}
}
}
我确信可以根据changeDescription.SessionId识别用户。但此刻我不知道如何......
编辑:这应该是可能的
public static WindowsIdentity GetUserName(int sessionId)
{
foreach (Process p in Process.GetProcesses())
{
if(p.SessionId == sessionId) {
return new WindowsIdentity(p.Handle);
}
}
return null;
}
MSDN链接
答案 1 :(得分:4)
最直接的方法是在每个用户的会话中运行一个小应用程序。此应用程序的每个实例都可以与服务的主要实例进行通信。
Windows非常难以将登录会话分开 - 包括服务和交互式桌面之间以及各个终端服务会话之间 - 因此除非您的应用程序正在运行,否则访问有关用户会话的此类信息变得非常棘手在该会议中开始。
答案 2 :(得分:2)
更简单的解决方案是使用包含各种TS API的Cassia来检查用户空闲的时间:
using Cassia;
foreach (ITerminalServicesSession session in new TerminalServicesManager().GetSessions())
{
if ((session.CurrentTime - session.LastInputTime > TimeSpan.FromMinutes(10)) &&
(!string.IsNullOrEmpty(session.UserName)))
{
Console.WriteLine("Session {0} (User {1}) is idle", session.SessionId, session.UserName);
}
}