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

我正在编写一个应用程序,有时会以通知消息的forms向用户发送通知。

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

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

我自己在Windows 7上,但我更喜欢一个普遍适用于Windows XP的解决scheme。

有没有文件的方式来找出工作站是否目前被锁定。 但是,您可以在取消/锁定时收到通知。 订阅SystemEvents.SessionSwitch事件,您将获得SessionSwitchReason.SessionLock和Unlock。

节电器也很麻烦。 当屏幕保护程序打开时,主窗口获取WM_SYSCOMMAND消息,SC_SCREENSAVE。 您可以锁住SystemParametersInfo来检查它是否正在运行。 你会在这个线程的答案中找到这个示例代码。

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

我最近再次从以前的博客文章中检查了这个代码,以确保它可以在Windows XP到7,x86和x64的版本上工作,并将其清理了一下。

这里是最新的最低限度的代码,检查工作站是否被锁定,如果屏幕保护程序运行包装在两个易于使用的静态方法:

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; } } } 

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

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

使用SystemParametersInfo检测屏幕保护程序是否正在运行 – calltype是SPI_GETSCREENSAVERRUNNING。 这是Win2000及以上版本支持的。

在这里有StackOverflow的@dan_g代码来检查wksta是否被锁定。

用户无法看到您的通知还有很多原因,例如全屏视频回放,或者用户不在。

我建议不要检查是否可以显示通知检查用户是否在那里,你可以通过监视键盘和鼠标来实现。

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

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