以编程方式停用屏幕保护程序

问题描述

我有一台 ACEPC T6,带有通过 HDMI 连接的 7 英寸 LCD 屏幕和一个 USB 触摸屏。
该系统通过 USB 串行链路连接到处理器板,该 USB 串行链路读取各种传感器并将数据反馈给 PC。
PC上的程序是用VB.NET 2019编写的。一切正常,只有一个例外。

我在活动 10 分钟后使用 ScreenSaver 使屏幕变黑,然后触摸屏幕恢复正常。

我的问题是我有一个 PIR 传感器连接到处理器,它将命令发送回 PC。我的目标是模拟被触摸的屏幕,并恢复显示,即当有人走进房间时,显示返回。

我尝试了各种选项,模拟鼠标效果,发送按键,但都无济于事。
任何帮助将不胜感激。

我应该提到我正在运行 Windows 10 专业版

解决方法

您可能无法使用 SendInput() 或其他函数获得肯定的结果,因为 ScreenSaver 在特殊桌面上运行,名为(猜猜看)Screen-saver
您需要获取此桌面的句柄才能与其或其 Windows 主动交互。

可以使用SystemParametersInfo函数,传递SPI_GETSCREENSAVERRUNNING来判断当前是否有一个ScreenSaver处于活动状态,然后调用OpenDesktop()获取桌面的句柄(使用它的名称),找到屏幕保护程序窗口(屏幕保护程序是一个标准的可执行文件)并发布一条 WM_CLOSE 消息来关闭它。

在这里,我使用 EnumDesktopWindows 来查找屏幕保护程序。
无论如何,屏幕保护程序窗口应该是前景窗口)。
如果失败,我们可以尝试关闭桌面,调用 CloseDesktop()

这里有一些与 ScreenSaver 相关的更有趣的信息:
Handling Screen Savers

如果您有通过串口或类似方式接收命令的过程,请验证此过程是否在 UI 线程以外的线程中运行,以防您在这种情况下需要访问 UI。

将此代码添加到过程中:它检查屏幕保护程序是否处于活动状态并尝试将其关闭。
它已在 Windows 10 (19H2) 和 Windows 7 SP1 中进行了测试。
.Net 框架 4.8 - VB.Net v.15

注意:您的应用旨在作为 64 位进程运行。如果您在项目的构建选项中设置了 Prefer 32-bit,则需要 取消选择它。

► 假设此过程在 UI 线程中运行。 Me.Activate() 不是严格要求的,只能从 UI Tread 中使用。如果您的代码在不同的线程上运行,请将其删除。

Protected Sub SomeProcedure()
    If NativeMethods.GetScreenSaverActiveState() Then
        NativeMethods.TerminateScreenSaver()
        Me.Activate()
    End If
End Sub

NativeMethods 类和辅助方法:

Imports System.Runtime.InteropServices
Imports System.Security.Permissions

Friend Class NativeMethods
    Private Const WM_CLOSE As Integer = &H10
    Private Const SPI_GETSCREENSAVERRUNNING As UInteger = &H72

    Public Enum DesktopAccessRights As Long
        DESKTOP_CREATEMENU = &H4L
        DESKTOP_CREATEWINDOW = &H2L
        DESKTOP_ENUMERATE = &H40L
        DESKTOP_HOOKCONTROL = &H8L
        DESKTOP_JOURNALPLAYBACK = &H20L
        DESKTOP_JOURNALRECORD = &H10L
        DESKTOP_READOBJECTS = &H1L
        DESKTOP_SWITCHDESKTOP = &H100L
        DESKTOP_WRITEOBJECTS = &H80L
    End Enum

    Private Delegate Function EnumWindowsProc(hDesktop As IntPtr,lParam As IntPtr) As Boolean

    <DllImport("user32.dll",CharSet:=CharSet.Unicode,SetLastError:=True)>
    Private Shared Function OpenDesktop(
        lpszDesktop As String,dwFlags As UInteger,<[In],MarshalAs(UnmanagedType.Bool)> fInherit As Boolean,dwDesiredAccess As DesktopAccessRights) As IntPtr
    End Function

    <DllImport("user32.dll",SetLastError:=True)>
    Private Shared Function CloseDesktop(hDesktop As IntPtr) As Boolean
    End Function

    <DllImport("user32.dll",SetLastError:=True)>
    Private Shared Function EnumDesktopWindows(
        hDesktop As IntPtr,callback As EnumWindowsProc,lParam As IntPtr) As Boolean
    End Function

    <DllImport("user32.dll",SetLastError:=True)>
    Public Shared Function GetForegroundWindow() As IntPtr
    End Function

    <DllImport("user32.dll",SetLastError:=True)>
    Private Shared Function IsWindowVisible(hWnd As IntPtr) As <MarshalAs(UnmanagedType.Bool)> Boolean
    End Function

    <DllImport("user32.dll",SetLastError:=True)>
    Private Shared Function PostMessage(hWnd As IntPtr,msg As UInteger,wParam As IntPtr,CharSet:=CharSet.Auto,SetLastError:=True)>
    Private Shared Function SystemParametersInfo(uiAction As UInteger,uiParam As UInteger,ByRef pvParam As IntPtr,fWinIni As UInteger) As Boolean
    End Function


    <UIPermission(SecurityAction.Demand,Action:=SecurityAction.Demand,Window:=UIPermissionWindow.AllWindows)>
    Private Shared Sub TerminateScreenSaverCore()
        Call New SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Demand()

        Dim hDesktop As IntPtr = OpenDesktop("Screen-saver",False,DesktopAccessRights.DESKTOP_READOBJECTS Or DesktopAccessRights.DESKTOP_WRITEOBJECTS)

        If hDesktop <> IntPtr.Zero Then
            If Not EnumDesktopWindows(hDesktop,Function(hWnd,lp)
                If IsWindowVisible(hWnd) Then CloseWindow(hWnd)
                Return True
            End Function,IntPtr.Zero) Then
                If Not CloseDesktop(hDesktop) Then
                    CloseWindow(GetForegroundWindow())
                End If
            End If
        End If
    End Sub

    Private Shared Sub CloseWindow(hWnd As IntPtr)
        PostMessage(hWnd,WM_CLOSE,IntPtr.Zero,IntPtr.Zero)
    End Sub

    Public Shared Sub TerminateScreenSaver()
        Try
            TerminateScreenSaverCore()
        Catch wex As Win32Exception
            MessageBox.Show(wex.Message)
        End Try
    End Sub

    Public Shared Function GetScreenSaverActiveState() As Boolean
        Dim scState As IntPtr = IntPtr.Zero
        SystemParametersInfo(SPI_GETSCREENSAVERRUNNING,0UI,scState,0UI)
        Return scState <> IntPtr.Zero
    End Function
End Class

C# 版本,以防万一:

using System.Runtime.InteropServices;
using System.Security.Permissions;

internal static class NativeMethods
{
    private const uint SPI_GETSCREENSAVERRUNNING = 0x0072;
    private const int WM_CLOSE = 0x0010;

    public enum DesktopAccessRights : long
    {
        DESKTOP_CREATEMENU = 0x0004L,// Required to create a menu on the desktop.
        DESKTOP_CREATEWINDOW = 0x0002L,// Required to create a window on the desktop.
        DESKTOP_ENUMERATE = 0x0040L,// Required for the desktop to be enumerated.
        DESKTOP_HOOKCONTROL = 0x0008L,// Required to establish any of the window hooks.
        DESKTOP_JOURNALPLAYBACK = 0x0020L,// Required to perform journal playback on a desktop.
        DESKTOP_JOURNALRECORD = 0x0010L,// Required to perform journal recording on a desktop.
        DESKTOP_READOBJECTS = 0x0001L,// Required to read objects on the desktop.
        DESKTOP_SWITCHDESKTOP = 0x0100L,// Required to activate the desktop using the SwitchDesktop function.
        DESKTOP_WRITEOBJECTS = 0x0080L       // Required to write objects on the desktop.
    }

    private delegate bool EnumWindowsProc(IntPtr hDesktop,IntPtr lParam);

    [DllImport("user32.dll",CharSet = CharSet.Unicode,SetLastError = true)]
    private static extern IntPtr OpenDesktop(
        string lpszDesktop,uint dwFlags,[In,MarshalAs(UnmanagedType.Bool)]bool fInherit,DesktopAccessRights dwDesiredAccess);

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

    [DllImport("user32.dll",SetLastError = true)]
    private static extern bool EnumDesktopWindows(IntPtr hDesktop,EnumWindowsProc callback,SetLastError = true)]
    private static extern bool IsWindowVisible(IntPtr hWnd);

    [DllImport("user32.dll",SetLastError = true)]
    public static extern IntPtr GetForegroundWindow();

    [DllImport("user32.dll",SetLastError = true)]

    [DllImport("user32.dll",SetLastError = true)]
    private static extern bool PostMessage(IntPtr hWnd,uint msg,IntPtr wParam,CharSet = CharSet.Auto,SetLastError = true)]
    private static extern bool SystemParametersInfo(uint uiAction,uint uiParam,ref IntPtr pvParam,uint fWinIni);


    [UIPermission(SecurityAction.Demand,Action = SecurityAction.Demand,Window = UIPermissionWindow.AllWindows)]
    public static void TerminateScreenSaverCore()
    {
        new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Demand();

        IntPtr hDesktop = OpenDesktop("Screen-saver",false,DesktopAccessRights.DESKTOP_READOBJECTS | DesktopAccessRights.DESKTOP_WRITEOBJECTS);
        if (hDesktop != IntPtr.Zero) {
            if (!EnumDesktopWindows(hDesktop,(hWnd,lp)=> {
                if (IsWindowVisible(hWnd)) CloseWindow(hWnd);
                return true;
            },IntPtr.Zero) || !CloseDesktop(hDesktop)) {
                CloseWindow(GetForegroundWindow());
            }
        }
    }

    private static void CloseWindow(IntPtr hWnd)
    {
        PostMessage(hWnd,IntPtr.Zero);
    }

    public static void TerminateScreenSaver()
    {
        try {
            TerminateScreenSaverCore();
        }
        catch(Win32Exception wex){
            MessageBox.Show(wex.Message);
        }
    }

    public static bool GetScreenSaverActiveState()
    {
        var scState = IntPtr.Zero;
        SystemParametersInfo(SPI_GETSCREENSAVERRUNNING,0U,ref scState,0U);
        return scState != IntPtr.Zero;
    }
}

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...