以编程方式中断活动的屏幕保护程序?

8

原因: 我正在开发一款紧急警报应用程序,需要在桌面上显示信息。当客户端收到警报时,会弹出一个窗口。如果屏幕保护程序处于活动状态或监视器处于待机状态,则警报将不可见。我想知道是否可能通过某种编程的鼠标移动或系统调用唤醒计算机,以便警报能够显示。我认为鼠标移动或按键唤醒它的原因是由于硬件中断,因此可能不可能实现。

目前,该项目正在使用C#实现。 我对Windows,MAC和Linux的解决方案感兴趣。

这是客户的要求。我已考虑以下内容:

  • 在大多数计算机上,在不活动后,用户必须登录。这些计算机将无法收到警报
  • 如果屏幕保护程序处于活动状态,则很有可能没有人在计算机旁边。

我不想做的事情:

  • 完全防止屏幕保护程序或节能模式被激活。
2个回答

4
建立在fbonnet所说的基础上,如果要在C#中使用kb文章中显示的函数,则pinvoke.net网站是一个很好的资源。他们还有一篇关于PostMessage函数的文章here
因此,使您的代码正常工作的基本方法可能是在pinvoke.net网站上搜索kb文章中列出的函数。或者您可以阅读this article已经为您完成了这项工作。

0

编程中一种打断屏幕保护的方法是移动鼠标光标。然而,在Windows上,这并不像看起来那么简单。

Windows操作系统有一个对象层次结构。在层次结构的顶部是“窗口站”。其下方是“桌面”(不要与桌面文件夹或甚至显示该文件夹图标的桌面窗口混淆)。您可以在文档中了解更多关于此概念的信息。

我提到这一点是因为通常情况下,任何时候只有一个桌面可以接收和处理用户输入。当由于超时而由Windows激活屏幕保护程序时,Windows会创建一个新的桌面来运行屏幕保护程序。

这意味着与任何其他桌面相关联的应用程序,包括您编写的正在运行的程序,将无法发送输入到新的桌面,除非进行一些额外的工作。该工作的性质取决于几个因素。假设最简单的情况是创建了一个没有“恢复时显示登录屏幕”的屏幕保护程序,并且没有通过远程连接或本地用户登录创建其他窗口站,则可以向Windows请求活动桌面,将Python脚本附加到该桌面,移动鼠标,然后恢复到以前的桌面,以便脚本的其余部分按预期工作。

值得庆幸的是,执行此操作的代码比解释更容易:

using System;
using System.Runtime.InteropServices;

namespace Example
{
    class Program
    {
        const uint MAXIMUM_ALLOWED = 0x02000000;

        [DllImport("user32.dll", SetLastError = true)]
        static extern IntPtr OpenInputDesktop(uint dwFlags, bool fInherit, uint dwDesiredAccess);
        [DllImport("user32.dll", SetLastError = true)]
        static extern IntPtr GetThreadDesktop(uint dwThreadId);
        [DllImport("user32.dll", SetLastError = true)]
        static extern bool SetThreadDesktop(IntPtr hDesktop);
        [DllImport("user32.dll")]
        static extern bool SetCursorPos(int x, int y);
        [DllImport("kernel32.dll")]
        static extern uint GetCurrentThreadId();

        static void Main(string[] args)
        {
            // Get a handle to the current active Desktop
            IntPtr hDesk = OpenInputDesktop(0, false, MAXIMUM_ALLOWED);
            // Get a handle to the Desktop this process is associated with
            IntPtr hDeskOld = GetThreadDesktop(GetCurrentThreadId());
            // Set this process to handle messages and input on the active Desktop
            SetThreadDesktop(hDesk);
            // Move the mouse cursor some
            for (int i = 0; i < 10; i ++)
            {
                SetCursorPos(i, i);
            }
            // Revert back to the old desktop association so the rest of this program works
            SetThreadDesktop(hDeskOld);
        }
    }
}

然而,如果屏幕保护程序在单独的窗口站点上运行,因为选择了“恢复时显示登录屏幕”,或者另一个用户通过物理控制台连接或远程连接,则连接和附加到活动桌面将需要提升程序权限,即使如此,根据其他因素,它可能需要特殊权限。

虽然这对于特定用例可能有效,但我要补充的是,在一般情况下,核心问题更适合定义为“如何通知用户某些状态,而不被屏幕保护程序阻止?”答案不是“让屏幕保护程序结束”,而是“使用类似 SetThreadExecutionState()ES_DISPLAY_REQUIRED 的东西来防止屏幕保护程序运行。并显示一个全屏顶部窗口,显示当前状态,并在想要警示用户时闪烁引人注目的图形和/或播放声音以引起他们的注意。”

虽然需要更多的工作,但这样做将解决在“恢复时显示登录屏幕”设置下安全桌面周围的问题,并防止系统进入睡眠状态(如果配置为这样)。它通常允许应用程序更清晰地传达其意图。

除此之外,屏幕保护程序的显示以及如何防止或中断它本质上是一个特定于操作的努力。Linux和MacOS将需要不同的技术来与系统交互。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接