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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/248186/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 19:47:56  来源:igfitidea点击:

Service needs to detect if workstation is locked, and screen saver is active

c#.net

提问by Brian Cline

I'm working on a service that needs to detect user states for all user(s) logged on to a single machine. Specifically, I want to check to see whether or not the screen saver is active and whether or not their session is locked.

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

This code will run under a system-level service, and has no visible UI, so that may rule out several options (trapping WM messages, etc).

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

Aside from normal workstations, I'd like for this to work on terminal servers that have multiple users logged in to it. Due to these requirements I'm wondering if several Win32 APIs will need to be involved.

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

Any ideas on where to begin?

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

采纳答案by Tim Robinson

The most straightforward way would be to have a small app running in each user's session. Each instance of this app could communicate with the main instance of the service.

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

Windows tries pretty hard to keep logon sessions separate -- both between services and the interactive desktop, and between individual Terminal Services sessions -- so it gets very tricky to access this sort of information about a user's session unless your app is running in that session to begin with.

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

回答by Dan Ports

A simpler solution would be to use Cassia, which wraps the various TS APIs, to check how long users have been idle for:

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

回答by Michael Piendl

As a serivce you can use the event OnSessionChange to catch all your relevant moments.

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

I'm sure it is possible to identify the user based on changeDescription.SessionId. But at the moment i don't know how...

我确信可以根据 changeDescription.SessionId 识别用户。但目前我不知道如何...

EDIT: This should be a possibilty

编辑:这应该是一种可能性

    public static WindowsIdentity GetUserName(int sessionId)
    {
        foreach (Process p in Process.GetProcesses())
        {
            if(p.SessionId == sessionId) {                    
                return new WindowsIdentity(p.Handle);                          
            }                
        }
        return null;
    }

MSDN Links

MSDN 链接