Деактивировать заставку программно

У меня есть ACEPC T6 с 7-дюймовым ЖК-экраном, подключенным через HDMI, и сенсорным экраном USB.
Эта система подключена к плате процессора через последовательный порт USB, который считывает данные с различных датчиков и передает данные обратно на ПК. .
Программа на ПК написана на VB.NET 2019. Все работает отлично за одним исключением.

Я использую заставку, чтобы очистить экран после 10 минут активности, и прикосновение к экрану возвращает все в нормальное состояние.

Моя проблема в том, что у меня есть датчик PIR, подключенный к процессору, который отправляет команду обратно на ПК. Моя цель состоит в том, чтобы имитировать прикосновение к экрану и восстановить отображение, т.е. когда кто-то входит в комнату, дисплей возвращается.

Я пробовал всевозможные варианты, имитируя эффекты мыши, отправляя нажатия клавиш, но все безрезультатно.
Буду признателен за любую помощь.

Я должен был упомянуть, что я использую Windows 10 Pro.


person Ian Pestell    schedule 14.02.2021    source источник
comment
Команда отправляется по серийному каналу, ПК, просто как номер. Число интерпретируется программой и затем может выполнять любую запрограммированную функцию, такую ​​как Sendinput(), которая не сработала. Это система мониторинга/управления/отчетности для моего большого морского аквариума.   -  person Ian Pestell    schedule 14.02.2021
comment
Пробовали ли вы этот ответ   -  person F0r3v3r-A-N00b    schedule 15.02.2021
comment
@ F0r3v3r-A-N00b Спасибо, там была полезная информация.   -  person Ian Pestell    schedule 15.02.2021


Ответы (1)


Вероятно, вы не сможете получить положительный результат, используя SendInput() или другие функции, потому что экранная заставка работает на специальном рабочем столе с именем (угадайте, как) Screen-saver.
Вам нужно получить дескриптор на этот рабочий стол, чтобы активно взаимодействовать с ним или его Windows.

Вы можете использовать функцию SystemParametersInfo. , передав SPI_GETSCREENSAVERRUNNING, чтобы определить, активна ли в данный момент заставка, затем вызовите OpenDesktop() получить дескриптор рабочего стола (используя его имя), найти окно заставки (заставка является стандартным исполняемым файлом) и опубликуйте WM_CLOSE сообщение, чтобы закрыть его.

Здесь я использую EnumDesktopWindows чтобы найти заставку.
(Окно заставки в любом случае должно быть окном переднего плана).
В случае неудачи мы можем попытаться закрыть рабочий стол, вызвав CloseDesktop().

Еще немного интересной информации о ScreenSaver здесь:
Работа с хранителями экрана

Если у вас есть процедура, которая получает команду через последовательный порт или что-то подобное, проверьте, выполняется ли эта процедура в потоке, отличном от потока пользовательского интерфейса, на случай, если вам потребуется доступ к пользовательскому интерфейсу в этом случае.

Добавьте этот код в процедуру: он проверяет, активна ли экранная заставка, и пытается ее закрыть.
Он был протестирован как в Windows 10 (19H2), так и в Windows 7 SP1.
.Net Framework 4.8 — VB. Сетка v.15

ПРИМЕЧАНИЕ: ваше приложение должно работать как 64-битный процесс. Если вы установили Prefer 32-bit в параметре сборки вашего проекта, вам необходимо отменить его выбор.

► Предположим, что эта процедура выполняется в потоке пользовательского интерфейса. 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
    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

    <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", 0, 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

    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", CharSet:=CharSet.Unicode, SetLastError:=True)>
    Private Shared Function CloseDesktop(hDesktop As IntPtr) As Boolean
    End Function

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

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

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

    <DllImport("user32.dll", CharSet:=CharSet.Unicode, SetLastError:=True)>
    Private Shared Function PostMessage(hWnd As IntPtr, msg As UInteger, wParam As IntPtr, lParam As IntPtr) As Boolean
    End Function

    <DllImport("user32.dll", 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
End Class

Версия С#, на всякий случай:

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

internal static class NativeMethods
{
    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;
    }

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

        IntPtr hDesktop = OpenDesktop("Screen-saver", 0, 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, WM_CLOSE, IntPtr.Zero, IntPtr.Zero);
    }

    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", CharSet = CharSet.Unicode, SetLastError = true)]
    private static extern bool CloseDesktop(IntPtr hDesktop);

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

    [DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    private static extern bool IsWindowVisible(IntPtr hWnd);

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

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

    [DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    private static extern bool PostMessage(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);

    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern bool SystemParametersInfo(uint uiAction, uint uiParam, ref IntPtr pvParam, uint fWinIni);
}
person Jimi    schedule 15.02.2021
comment
Отлично, я попробую и дам вам знать. - person Ian Pestell; 15.02.2021
comment
Большое спасибо, с парой мелких модов он делает именно то, что я хотел. - person Ian Pestell; 16.02.2021