检测屏幕保护程序是否处于活动状态和/或用户是否已在 Windows 中锁定屏幕

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3953297/
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-09-15 15:25:34  来源:igfitidea点击:

Detecting if the screensaver is active and/or the user has locked the screen in Windows

c#windows

提问by Pieter

I'm writing an app that at times will send notifications to the user in the form of toaster messages.

我正在编写一个应用程序,它有时会以烤面包机消息的形式向用户发送通知。

If the user is not there, he can't see the notification. So what I wanna do is be able to check if the user has locked the screen or if the screensaver happens to be activated.

如果用户不在,他就看不到通知。所以我想要做的是能够检查用户是否锁定了屏幕或者屏幕保护程序是否被激活。

Any notification that is triggered while the user cannot see it will be delayed and shown when the user logs back in and resumes his session.

当用户无法看到时触发的任何通知将被延迟并在用户重新登录并恢复其会话时显示。

I'm on Windows 7 myself, but I'd prefer a solution that works universally for Windows XP and up.

我自己使用的是 Windows 7,但我更喜欢一种普遍适用于 Windows XP 及更高版本的解决方案。

回答by Hans Passant

There is no documented way to find out if the workstation is currently locked. You can however get a notification when it un/locks. Subscribe the SystemEvents.SessionSwitch event, you'll get SessionSwitchReason.SessionLock and Unlock.

没有记录的方法来确定工作站当前是否被锁定。但是,您可以在解锁/锁定时收到通知。订阅 SystemEvents.SessionSwitch 事件,您将获得 SessionSwitchReason.SessionLock 和 Unlock。

The sceen saver is troublesome too. Your main window gets the WM_SYSCOMMAND message, SC_SCREENSAVE when the screen saver turns on. You can pinvoke SystemParametersInfo to check if it running. You'll find sample code for this in my answer in this thread.

屏幕保护程序也很麻烦。当屏幕保护程序打开时,您的主窗口会收到 WM_SYSCOMMAND 消息 SC_SCREENSAVE。您可以调用 SystemParametersInfo 来检查它是否正在运行。您将在此线程的我的回答中找到此示例代码。

There is no good way to find out if the user fell asleep.

没有很好的方法来确定用户是否睡着了。

回答by BrutalDev

I have recently checked this code again from a previous blog postto ensure it works on versions of Windows XP to 7, x86 and x64 and cleaned it up a bit.

我最近从之前的一篇博客文章中再次检查了这段代码,以确保它适用于 Windows XP 到 7、x86 和 x64 的版本,并对其进行了一些清理。

Here is the latest minimalist code that checks if the workstation is locked and if the screensaver is running wrapped in two easy to use static methods:

这是最新的简约代码,用于检查工作站是否已锁定以及屏幕保护程序是否正在运行,包含在两个易于使用的静态方法中:

using System;
using System.Runtime.InteropServices;

namespace BrutalDev.Helpers
{
  public static class NativeMethods
  {
    // Used to check if the screen saver is running
    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool SystemParametersInfo(uint uAction, 
                                                   uint uParam, 
                                                   ref bool lpvParam,
                                                   int fWinIni);

    // Used to check if the workstation is locked
    [DllImport("user32", SetLastError = true)]
    private static extern IntPtr OpenDesktop(string lpszDesktop,
                                             uint dwFlags,
                                             bool fInherit,
                                             uint dwDesiredAccess);

    [DllImport("user32", SetLastError = true)]
    private static extern IntPtr OpenInputDesktop(uint dwFlags,
                                                  bool fInherit,
                                                  uint dwDesiredAccess);

    [DllImport("user32", SetLastError = true)]
    private static extern IntPtr CloseDesktop(IntPtr hDesktop);

    [DllImport("user32", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool SwitchDesktop(IntPtr hDesktop);

    // Check if the workstation has been locked.
    public static bool IsWorkstationLocked()
    {
      const int DESKTOP_SWITCHDESKTOP = 256;
      IntPtr hwnd = OpenInputDesktop(0, false, DESKTOP_SWITCHDESKTOP);

      if (hwnd == IntPtr.Zero)
      {
        // Could not get the input desktop, might be locked already?
        hwnd = OpenDesktop("Default", 0, false, DESKTOP_SWITCHDESKTOP);
      }

      // Can we switch the desktop?
      if (hwnd != IntPtr.Zero)
      {
        if (SwitchDesktop(hwnd))
        {
          // Workstation is NOT LOCKED.
          CloseDesktop(hwnd);
        }
        else
        {
          CloseDesktop(hwnd);
          // Workstation is LOCKED.
          return true;
        }
      }

      return false;
    }

    // Check if the screensaver is busy running.
    public static bool IsScreensaverRunning()
    {
      const int SPI_GETSCREENSAVERRUNNING = 114;
      bool isRunning = false;

      if (!SystemParametersInfo(SPI_GETSCREENSAVERRUNNING, 0, ref isRunning, 0))
      {
        // Could not detect screen saver status...
        return false;
      }

      if (isRunning)
      {
        // Screen saver is ON.
        return true;
      }

      // Screen saver is OFF.
      return false;
    }
  }
}

UPDATE: Code updated based on suggestions in the comments.

更新:根据评论中的建议更新代码。

When the workstation is locked then the OpenInputDesktopmethod does not return a handle so we can fall-back on OpenDesktopfor a handle to make sure it's locked by trying to switch. If it's not locked then your default desktop will not be activated since OpenInputDesktopwill return a valid handle for the desktop you are viewing.

当工作站被锁定时,OpenInputDesktop方法不会返回句柄,因此我们可以在OpenDesktop 上回退一个句柄,以确保它通过尝试切换而被锁定。如果它没有被锁定,那么您的默认桌面将不会被激活,因为OpenInputDesktop将为您正在查看的桌面返回一个有效的句柄。

回答by Steve Townsend

Use SystemParametersInfoto detect whether screen saver is running - the calltype is SPI_GETSCREENSAVERRUNNING. This is supported on Win2000 and above.

使用SystemParametersInfo检测屏幕保护程序是否正在运行 - 调用类型为 SPI_GETSCREENSAVERRUNNING。这在 Win2000 及更高版本上受支持。

There is code from @dan_g on StackOverflow hereto check if wksta is locked.

有一个从StackOverflow上@dan_g代码在这里检查,如果WKSTA被锁定。

回答by Shay Erlichmen

There are many reason why the user can't see your notifications also for example full screen video playback or that the user is just not there.

用户看不到您的通知的原因有很多,例如全屏视频播放或用户不在那里。

I suggest that instead of checking if the notification can be displayed check if the user is there, you can do that by monitoring the keyboard and mouse.

我建议不要检查是否可以显示通知,而是检查用户是否在那里,您可以通过监视键盘和鼠标来做到这一点。

回答by Chikku Jacob

SystemEvents.SessionSwitch += new SessionSwitchEventHandler((sender, e) =>
        {
            switch (e.Reason)
            {
                //If Reason is Lock, Turn off the monitor.
                case SessionSwitchReason.SessionLock:
                    //SendMessage(HWND_BROADCAST, WM_SYSCOMMAND, SC_MONITORPOWER, MONITOR_OFF);
                    MessageBox.Show("locked");
                    break;

                case SessionSwitchReason.SessionUnlock:
                    MessageBox.Show("unlocked");
                    break;
            }
        });

This will indicate when the session is Locked and Unlocked.

这将指示会话何时被锁定和解锁。

回答by Christopher Painter

In researching this question I found a couple techniques that support detecting if the workstation is locked. One is really simple:

在研究这个问题时,我发现了一些支持检测工作站是否被锁定的技术。一个非常简单:

bool locked = Process.GetProcessesByName("logonui").Any();

This works because the logonui process is only running when the desktop is locked.

这是有效的,因为 logonui 进程仅在桌面锁定时运行。

Another more complicated approach is to walk the system event log backwards looking for event ids 4800 and 4801. These indicate when a machine is locked and unclocked.

另一种更复杂的方法是向后遍历系统事件日志以查找事件 ID 4800 和 4801。这些指示机器何时锁定和解锁。

More detail can be found at:

可以在以下位置找到更多详细信息:

https://superuser.com/questions/1170918/determine-remote-windows-screen-locked-or-unlocked-remotely

https://superuser.com/questions/1170918/determine-remote-windows-screen-locked-or-unlocked-remotely

http://mctexpert.blogspot.com/2012/10/how-to-determine-if-client-on-your.html

http://mctexpert.blogspot.com/2012/10/how-to-determine-if-client-on-your.html

The latter requires audit policies to be set which are the default anyways. I work in an enterprise IT organization so it's not a concern for me as I'm certain those settings are applied.

后者需要设置审计策略,无论如何都是默认的。我在一家企业 IT 组织工作,所以这对我来说不是问题,因为我确定应用了这些设置。