【问题标题】:Service needs to detect if workstation is locked, and screen saver is active服务需要检测工作站是否被锁定,屏幕保护程序是否处于活动状态
【发布时间】:2009-04-09 21:01:13
【问题描述】:

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

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

除了普通的工作站,我希望它可以在有多个用户登录的终端服务器上工作。由于这些要求,我想知道是否需要涉及多个 Win32 API。

关于从哪里开始有什么想法吗?

【问题讨论】:

    标签: c# .net


    【解决方案1】:

    作为一项服务,您可以使用事件 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 链接

    【讨论】:

    【解决方案2】:

    最直接的方法是在每个用户的会话中运行一个小应用程序。此应用的每个实例都可以与服务的主实例进行通信。

    Windows 非常努力地将登录会话分开——在服务和交互式桌面之间,以及在各个终端服务会话之间——因此访问有关用户会话的此类信息变得非常棘手,除非您的应用正在运行在该会话开始。

    【讨论】:

    • 谢谢,我试试看。也许一个简单的套接字是最好的方法。
    【解决方案3】:

    更简单的解决方案是使用封装了各种 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);
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-04-14
      • 2015-02-15
      • 2023-03-26
      • 1970-01-01
      • 1970-01-01
      • 2012-01-27
      • 2012-07-15
      相关资源
      最近更新 更多