服务需要检测工作站是否已锁定,并且屏幕保护程序处于活动状态

时间:2008-10-29 19:53:42

标签: c# .net

我正在开发一项服务,该服务需要检测登录到单台计算机的所有用户的用户状态。具体来说,我想检查屏幕保护程序是否处于活动状态以及会话是否被锁定。

此代码将在系统级服务下运行,并且没有可见的UI,因此可以排除多个选项(捕获WM消息等)。

除了正常的工作站之外,我还希望能够在有多个用户登录的终端服务器上工作。由于这些要求,我想知道是否需要涉及多个Win32 API。

关于从哪里开始的任何想法?

3 个答案:

答案 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);
    }
}