简体   繁体   English

在媒体播放期间从 C# 中的 WPF 应用程序在 Windows 上启用屏幕保护程序

[英]Enable Screensaver on Windows from WPF application in C# during media playback

I am new to WPF and c#.我是 WPF 和 C# 的新手。 I'm using in an simple WPF Application the MediaElement to play an looped video, using a Storyboard.我在一个简单的 WPF 应用程序中使用 MediaElement 来播放循环视频,使用情节提要。

Now in this Project I have a big problem.现在在这个项目中我有一个大问题。 The playing video in the MediaElement suppresses the screensaver from starting. MediaElement 中的播放视频会阻止屏幕保护程序启动。 But in my case, i need the normal windows behavior.但就我而言,我需要正常的 Windows 行为。 (Automatic screensaver and automatic log off and so on.) (自动屏幕保护程序和自动注销等。)

How can I make the normal screensaver appearing again, even if an video is playing in my MediaElement?即使在我的 MediaElement 中正在播放视频,我怎样才能让正常的屏幕保护程序再次出现?

The Code is simple: The Main Windows:代码很简单: 主窗口:

<Window x:Name="BrutusView" x:Class="BRUTUS_Panel_View.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:BRUTUS_Panel_View"
mc:Ignorable="d"
        Title="3nb BRUTUS Side Panel Player" Height="320" Width="256" HorizontalAlignment="Center" VerticalAlignment="Center" Left="0" Top="0" Deactivated="BrutusView_Deactivated" LostFocus="BrutusView_LostFocus" Loaded="BrutusView_Loaded" WindowStyle="ToolWindow" ResizeMode="CanResize" Icon="F:\Dokumente\Visual Studio 2015\Projects\BRUTUSConfig\BRUTUSConfig\3nb.ico" Topmost="True" ShowInTaskbar="False" ShowActivated="False" Visibility="Visible">
    <Grid>
        <MediaElement x:Name="myMediaElement" LoadedBehavior="Manual" HorizontalAlignment="Center"  VerticalAlignment="Center" IsMuted="True" Stretch="UniformToFill">
            <MediaElement.Triggers>
                <EventTrigger RoutedEvent="MediaElement.Loaded">
                    <EventTrigger.Actions>
                        <BeginStoryboard>
                            <Storyboard>
                                <MediaTimeline Source="C:\Animations\1.mp4" Storyboard.TargetName="myMediaElement" RepeatBehavior="Forever" />
                            </Storyboard>
                        </BeginStoryboard>
                    </EventTrigger.Actions>
                </EventTrigger>
            </MediaElement.Triggers>
        </MediaElement>
    </Grid>
</Window>

The c#: C#:

using System;
using System.Linq;
using System.Windows;
using System.Windows.Forms;
using System.Windows.Threading;

namespace BRUTUS_Panel_View
{

    public partial class MainWindow : Window
    {



        public MainWindow()
        {
            InitializeComponent();
        }

        private void BrutusView_Loaded(object sender, RoutedEventArgs e)
        {

        }

        private void BrutusView_Deactivated(object sender, EventArgs e)
        {
            BrutusView.Topmost = true;
        }

        private void BrutusView_LostFocus(object sender, RoutedEventArgs e)
        {
            BrutusView.Topmost = true;
        }

    }
}

Answer contains two solutions: (i) based on UWP DisplayRequest class, (ii) based on custom ScreenSaverManager class which is more general.答案包含两种解决方案:(i) 基于 UWP DisplayRequest类,(ii) 基于自定义ScreenSaverManager类,这是更通用的。

1. UWP DisplayRequest class 1. UWP DisplayRequest

Windows provides direct method to request suspension of screen saver and calling it successfully guarantees that screen saver will not start due to user inactivity ie during media playback. Windows 提供直接方法来请求暂停屏幕保护程序并成功调用它可以保证屏幕保护程序不会由于用户不活动而启动,即在媒体播放期间。 The reverse is possible with method enabling screen saver again.使用再次启用屏幕保护程序的方法可以反过来。 Both methods are available in Windows 10 (UWP Runtime) and can be accessed via Windows.System.Display.DisplayRequest class.这两种方法在 Windows 10(UWP 运行时)中都可用,并且可以通过Windows.System.Display.DisplayRequest类访问。 Example of how to use it outside of UWP applications - in WPF desktop application - is posted below.下面发布了如何在 UWP 应用程序之外(在 WPF 桌面应用程序中)使用它的示例。

Before working with code it is necessary to add to a standard WPF application created in Visual Studio from template the following references: (i) Windows.winmd from directory: C:\\Program Files (x86)\\Windows Kits\\10\\UnionMetadata and (ii) System.Runtime.WindowsRuntime.dll from directory: C:\\Program Files (x86)\\Reference Assemblies\\Microsoft\\Framework\\.NETCore\\v4.5.1 (or v4.5).在使用代码之前,有必要将以下引用添加到在 Visual Studio 中从模板创建的标准 WPF 应用程序中:(i) 来自目录的Windows.winmdC:\\Program Files (x86)\\Windows Kits\\10\\UnionMetadata和( ii) System.Runtime.WindowsRuntime.dll来自目录: C:\\Program Files (x86)\\Reference Assemblies\\Microsoft\\Framework\\.NETCore\\v4.5.1 (或 v4.5)。

To suspend or enable screen saver during playback hook start and stop of playaback events to relevant methods.在播放过程中暂停或启用屏幕保护程序将播放事件的开始和停止挂钩到相关方法。

using System;
using System.Windows;
using System.Windows.Controls;
using Windows.System.Display;

namespace SuspendScreenSaverWpf
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private DisplayRequest mDisplayRequest;

        public MainWindow()
        {
            InitializeComponent();
        }

        private void SuspendButton_Click(object sender, RoutedEventArgs e)
        {
            Button b = sender as Button;
            if (b != null)
            {
                try
                {
                    if (mDisplayRequest == null)
                    {
                        // This call creates an instance of the displayRequest object
                        mDisplayRequest = new DisplayRequest();
                    }
                }
                catch (Exception ex)
                {
                    this.MessageBoard.Content = $"Error Creating Display Request: {ex.Message}";
                }

                if (mDisplayRequest != null)
                {
                    try
                    {
                        // This call activates a display-required request. If successful,
                        // the screen is guaranteed not to turn off automatically due to user inactivity.
                        mDisplayRequest.RequestActive();
                        this.MessageBoard.Content = $"Display request activated - ScreenSaver suspended";
                        this.EnableButton.IsEnabled = true;
                        this.SuspendButton.IsEnabled = false;
                    }
                    catch (Exception ex)
                    {
                        this.MessageBoard.Content = $"Error: {ex.Message}";
                    }
                }
            }
        }

        private void EnableButton_Click(object sender, RoutedEventArgs e)
        {
            Button b = sender as Button;
            if (b != null)
            {
                if (mDisplayRequest != null)
                {
                    try
                    {
                        // This call de-activates the display-required request. If successful, the screen
                        // might be turned off automatically due to a user inactivity, depending on the
                        // power policy settings of the system. The requestRelease method throws an exception
                        // if it is called before a successful requestActive call on this object.
                        mDisplayRequest.RequestRelease();
                        this.MessageBoard.Content = $"Display request released - ScreenSaver enabled.";
                        this.SuspendButton.IsEnabled = true;
                        this.EnableButton.IsEnabled = false;
                    }
                    catch (Exception ex)
                    {
                        this.MessageBoard.Content = $"Error: {ex.Message}";
                    }
                }
            }
        }
    }
}



<Window x:Class="SuspendScreenSaverWpf.MainWindow"
                    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
                    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
                    xmlns:local="clr-namespace:SuspendScreenSaverWpf"
                    mc:Ignorable="d"
                    Title="MainWindow ScreenSaver management demo" Height="350" Width="525">
    <Grid>
        <Button x:Name="SuspendButton" IsEnabled="true" Content="Suspend ScreenSaver" HorizontalAlignment="Left" Margin="73,250,0,0" VerticalAlignment="Top" Width="150" Click="SuspendButton_Click"/>
        <Button x:Name="EnableButton" IsEnabled="False" Content="Enable ScreenSaver" HorizontalAlignment="Left" Margin="298,250,0,0" VerticalAlignment="Top" Width="150" Click="EnableButton_Click"/>
        <Label x:Name="MessageBoard" Content="Example project demonstrating how to disable ScreenSaver on Windows 10" HorizontalAlignment="Left" Height="78" Margin="73,39,0,0" VerticalAlignment="Top"  Width="375"/>

    </Grid>
</Window>

Another instruction on referencing assemblies in order to access Windows 10 UWP APIs can be found on a web page of UwpDesktop NuGet package .可以在UwpDesktop NuGet 包的网页上找到有关引用程序集以访问 Windows 10 UWP API 的另一条说明。 The UwpDesktop package itself seems to be not maintained for duration of at least last two Windows 10 Creators updates but could be still useful if targeting 10.0.14393 APIs. UwpDesktop 包本身似乎至少在最近两次 Windows 10 Creators 更新期间没有维护,但如果针对 10.0.14393 API 仍然有用。

For examples of how to use this method from C/C++ code see the repo of SDL Library有关如何从 C/C++ 代码使用此方法的示例,请参阅SDL 库的 repo

2. Custom ScreenSaverManager class 2.自定义ScreenSaverManager

Challenging part of the question is related to undocumented behavior of System.Windows.Controls.MediaElement control which suspends screen saver for the duration of media playback.问题的挑战部分与System.Windows.Controls.MediaElement控件的未记录行为有关,该控件在媒体播放期间暂停屏幕保护程序。 Despite the fact that preventing activation of screen saver is a good practice from the perspective of user watching movie there are applications where it is not desirable.尽管从用户观看电影的角度来看,阻止激活屏幕保护程序是一种很好的做法,但在某些应用程序中并不理想。 Obligatory disabling of screen saver or workstation lock out due to security reasons or when playing media is not most important application function is not a good practice.由于安全原因或当播放媒体不是最重要的应用程序功能时,强制禁用屏幕保护程序或工作站锁定不是一个好习惯。 Microsoft should provide a public property o method which could be used to control this functionality. Microsoft 应提供可用于控制此功能的公共属性 o 方法。

To avoid any hacks I have tried to solve problem using only Win32 and .NET/WPF public APIs.为了避免任何黑客攻击,我尝试仅使用 Win32 和 .NET/WPF 公共 API 来解决问题。 The simplest and yet most effective solution is based on creating our own ScreenSaverManager which duplicates OS functionality and enforces on demand original screen saver behavior ( automatic screensaver and automatic log off and so on ).最简单但最有效的解决方案是创建我们自己的ScreenSaverManager ,它复制操作系统功能并按需强制执行原始屏幕保护程序行为(自动屏幕保护程序和自动注销等)。 First ScreenSaverManager reads current session settings and based on them starts enforcing session policy bypassing methods used to block screen saver and session lock out by MediaElement .首先ScreenSaverManager读取当前会话设置,并基于它们开始强制执行会话策略绕过方法,用于阻止屏幕保护程序和由MediaElement锁定的会话。

using System;
using System.Timers;

namespace ManageScreenSaver.MediaElementWpf
{
    public class ScreenSaverManager
    {
        private static ScreenSaverManager _Manager;

        public static ScreenSaverManager Instance
        {
            get
            {
                if (_Manager != null)
                    return _Manager;

                _Manager = new ScreenSaverManager();
                return _Manager;
            }
        }

        private TimeSpan _ScreenSaverTimeout;
        private bool _IsScreenSaverSecure;
        private Timer _Timer;

        protected ScreenSaverManager()
        {
            _ScreenSaverTimeout = NativeMethods.ScreenSaverTimeout;
            _IsScreenSaverSecure = NativeMethods.IsScreenSaverSecure;
            _Timer = new Timer(_ScreenSaverTimeout.TotalMilliseconds/2);
            _Timer.AutoReset = false;
            _Timer.Elapsed += Timer_Elapsed;
            _Timer.Start();
        }

        private void Timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            var lastInput = NativeMethods.GetLastUserInputTimeInterval();
            MainWindow.Console.WriteLine($"Last user input interval: {lastInput}");
            if (lastInput >= _ScreenSaverTimeout)
            {
                StartScreenSaver();
            }
            else
            {
                _Timer.Interval = _ScreenSaverTimeout.Subtract(lastInput).TotalMilliseconds + 100;
                _Timer.Start();
            }
        }

        private void StartScreenSaver()
        {
            if (_IsScreenSaverSecure)
            {
                NativeMethods.LockWorkStationSession();
            }
            else
            {
                var result = NativeMethods.SendMessage((IntPtr) 0xffff, (uint) WindowMessage.WM_SYSCOMMAND, (uint) WmSysCommandParam.ScSCREENSAVE, 0);
            }
        }
    }
}

Interop methods are defined in separate class NativeMethods :互操作方法在单独的类NativeMethods中定义:

using System;
using System.ComponentModel;
using System.Runtime.InteropServices;

namespace ManageScreenSaver.MediaElementWpf
{
    public static class NativeMethods
    {
        public const uint SPI_GETSCREENSAVETIMEOUT = 0x000E;
        public const uint SPI_SETSCREENSAVETIMEOUT = 0x000F;
        public const uint SPI_GETSCREENSAVEACTIVE = 0x0010;
        public const uint SPI_SETSCREENSAVEACTIVE = 0x0011;
        public const uint SPI_SETSCREENSAVERRUNNING = 0x0061;
        public const uint SPI_SCREENSAVERRUNNING = SPI_SETSCREENSAVERRUNNING;
        public const uint SPI_GETSCREENSAVERRUNNING = 0x0072;
        public const uint SPI_GETSCREENSAVESECURE = 0x0076;
        public const uint SPI_SETSCREENSAVESECURE = 0x0077;

        public const uint SPIF_UPDATEINIFILE = 0x0001;
        public const uint SPIF_SENDWININICHANGE = 0x0002;
        public const uint SPIF_SENDCHANGE = SPIF_SENDWININICHANGE;

        [DllImport("user32.dll", CallingConvention = CallingConvention.Winapi, PreserveSig = true, SetLastError = true)]
        internal static unsafe extern bool SystemParametersInfo(uint  uiAction, uint  uiParam, void* pvParam, uint  fWinIni);

        [DllImport("user32.dll", CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Unicode, PreserveSig = true, SetLastError = true)]
        internal static extern IntPtr DefWindowProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled);

        [DllImport("user32.dll", SetLastError = true)]
        static extern bool GetLastInputInfo(ref LASTINPUTINFO plii);

        [DllImport("User32.dll", SetLastError = true)]
        internal static extern int SendMessage(IntPtr hWnd, uint msg, uint wParam, uint lParam);

        [DllImport("user32.dll", SetLastError = true)]
        internal static extern bool LockWorkStation();

        public static TimeSpan GetLastUserInputTimeInterval()
        {
            LASTINPUTINFO lastInputInfo = new LASTINPUTINFO();
            lastInputInfo.cbSize = (uint)Marshal.SizeOf(lastInputInfo);

            if (!GetLastInputInfo(ref lastInputInfo))
            {
                throw new Win32Exception(Marshal.GetLastWin32Error());
            }

            uint ticks = (uint)Environment.TickCount;
            var idleMiliseconds = ticks - lastInputInfo.dwTime;
            return idleMiliseconds > 0 ? TimeSpan.FromMilliseconds((double)idleMiliseconds) : default(TimeSpan);
        }


        public static void LockWorkStationSession()
        {
            if (!LockWorkStation())
            {
                throw new Win32Exception(Marshal.GetLastWin32Error());
            }
        }

        public static bool IsScreenSaverActive
        {
            get
            {
                bool enabled = false;
                unsafe
                {
                    var result = SystemParametersInfo(SPI_GETSCREENSAVEACTIVE, 0, &enabled, 0);
                    if (!result)
                    {
                        throw new Win32Exception(Marshal.GetLastWin32Error());
                    }
                    return enabled;
                }
            }
        }

        public static bool IsScreenSaverRunning
        {
            get
            {
                bool enabled = false;
                unsafe
                {
                    var result = SystemParametersInfo(SPI_GETSCREENSAVERRUNNING, 0, &enabled, 0);
                    if (!result)
                    {
                        throw new Win32Exception(Marshal.GetLastWin32Error());
                    }
                    return enabled;
                }
            }
        }

        public static bool IsScreenSaverSecure
        {
            get
            {
                bool enabled = false;
                unsafe
                {
                    var result = SystemParametersInfo(SPI_GETSCREENSAVESECURE, 0, &enabled, 0);
                    if (!result)
                    {
                        throw new Win32Exception(Marshal.GetLastWin32Error());
                    }
                    return enabled;
                }
            }
        }

        public static TimeSpan ScreenSaverTimeout
        {
            get
            {
                int timeout = 0;
                unsafe
                {
                    var result = SystemParametersInfo(SPI_GETSCREENSAVETIMEOUT, 0, &timeout, 0);
                    if (!result)
                    {
                        throw new Win32Exception(Marshal.GetLastWin32Error());
                    }
                    return TimeSpan.FromSeconds(timeout);
                }
            }
        }
    }

    [Flags]
    public enum WindowMessage : uint
    {
        WM_COMMAND = 0x0111,
        WM_SYSCOMMAND = 0x0112, 
    }

    public enum WmSysCommandParam : uint
    {
        ScSIZE        = 0xF000,
        ScMOVE        = 0xF010,
        ScMINIMIZE    = 0xF020,
        ScMAXIMIZE    = 0xF030,
        ScNEXTWINDOW  = 0xF040,
        ScPREVWINDOW  = 0xF050,
        ScCLOSE       = 0xF060,
        ScVSCROLL     = 0xF070,
        ScHSCROLL     = 0xF080,
        ScMOUSEMENU   = 0xF090,
        ScKEYMENU     = 0xF100,
        ScARRANGE     = 0xF110,
        ScRESTORE     = 0xF120,
        ScTASKLIST    = 0xF130,
        ScSCREENSAVE  = 0xF140,
        ScHOTKEY      = 0xF150,
        ScDEFAULT     = 0xF160,
        ScMONITORPOWER= 0xF170,
        ScCONTEXTHELP = 0xF180,
        ScSEPARATOR   = 0xF00F,
    }
 }   

Finally there is example on how to use ScreenSaverManager in WPF application:最后有一个关于如何在 WPF 应用程序中使用ScreenSaverManager示例:

<Window x:Class="ManageScreenSaver.MediaElementWpf.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:ManageScreenSaver.MediaElementWpf"
        mc:Ignorable="d"
        Title="MainWindow" Height="570" Width="550" MinHeight="570" MinWidth="550" MaxHeight="570" MaxWidth="550">
    <Grid Margin="0,0,0,0">
        <MediaElement x:Name="myMediaElement" Width="530" Height="270" LoadedBehavior="Manual" HorizontalAlignment="Center"  VerticalAlignment="Center" IsMuted="True" Stretch="Fill" Margin="10,52,10,197" >
            <MediaElement.Triggers>
                <EventTrigger RoutedEvent="MediaElement.Loaded">
                    <EventTrigger.Actions>
                        <BeginStoryboard>
                            <Storyboard>
                                <MediaTimeline Source="..\..\BigBuckBunny_320x180.mp4" Storyboard.TargetName="myMediaElement" RepeatBehavior="Forever" />
                            </Storyboard>
                        </BeginStoryboard>
                    </EventTrigger.Actions>
                </EventTrigger>
            </MediaElement.Triggers>
        </MediaElement>
        <Button x:Name="SuspendButton" IsEnabled="true" Content="Suspend ScreenSaver" HorizontalAlignment="Left" Margin="74,489,0,0" VerticalAlignment="Top" Width="150" Click="SuspendButton_Click" RenderTransformOrigin="0.501,2.334"/>
        <Button x:Name="EnableButton" IsEnabled="true" Content="Enable ScreenSaver" HorizontalAlignment="Left" Margin="302,489,0,0" VerticalAlignment="Top" Width="150" Click="EnableButton_Click" RenderTransformOrigin="0.508,1.359"/>
        <Label x:Name="MessageBoard" Content="Example project demonstrating how to disable ScreenSaver on Windows 10" HorizontalAlignment="Left" Height="25" Margin="44,10,0,0" VerticalAlignment="Top"  Width="432"/>
        <TextBox x:Name="TextBox" Text="" HorizontalAlignment="Center" HorizontalContentAlignment="Left" Height="110" Margin="10,342,10,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="510"/>
    </Grid>
</Window>

using System;
using System.Timers;
using System.Windows;
using System.Windows.Controls;
using Windows.System.Display;

namespace ManageScreenSaver.MediaElementWpf
{
    public partial class MainWindow : Window
    {
        private DisplayRequest mDisplayRequest;
        internal static TextBoxWriter Console;
        private static ScreenSaverManager _ScreenSaverManager;

        public MainWindow()
        {
            InitializeComponent();
            Console = new TextBoxWriter(this.TextBox);
            _ScreenSaverManager = ScreenSaverManager.Instance;
            PrintSSaverStatus(" MainWindow.ctor");
        }

        private void PrintSSaverStatus(string apendedText = "")
        {
            Console.WriteLine(GetScreenSaverStatusMessage() + apendedText);
        }

        private void SuspendButton_Click(object sender, RoutedEventArgs e)
        {
            Button b = sender as Button;
            if (b != null)
            {
                EnsureDisplayRequest();

                if (mDisplayRequest != null)
                {
                    try
                    {
                        // This call activates a display-required request. If successful,
                        // the screen is guaranteed not to turn off automatically due to user inactivity.
                        mDisplayRequest.RequestActive();
                        this.MessageBoard.Content = $"Display request activated - ScreenSaver suspended";
                        this.EnableButton.IsEnabled = true;
                        this.SuspendButton.IsEnabled = false;
                    }
                    catch (Exception ex)
                    {
                        this.MessageBoard.Content = $"Error: {ex.Message}";
                    }

                    PrintSSaverStatus(" SuspendButton_Click");
                }
            }
        }

        private void EnsureDisplayRequest()
        {
            try
            {
                if (mDisplayRequest == null)
                {
                    // This call creates an instance of the displayRequest object
                    mDisplayRequest = new DisplayRequest();
                }
            }
            catch (Exception ex)
            {
                this.MessageBoard.Content = $"Error Creating Display Request: {ex.Message}";
            }
        }

        private void EnableButton_Click(object sender, RoutedEventArgs e)
        {
            Button b = sender as Button;
            if (b != null)
            {
                EnsureDisplayRequest();

                if (mDisplayRequest != null)
                {
                    try
                    {
                        // This call de-activates the display-required request. If successful, the screen
                        // might be turned off automatically due to a user inactivity, depending on the
                        // power policy settings of the system. The requestRelease method throws an exception
                        // if it is called before a successful requestActive call on this object.
                        mDisplayRequest.RequestRelease();
                        this.MessageBoard.Content = $"Display request released - ScreenSaver enabled.";
                        this.SuspendButton.IsEnabled = true;
                        this.EnableButton.IsEnabled = false;
                    }
                    catch (Exception ex)
                    {
                        this.MessageBoard.Content = $"Error: {ex.Message}";
                    }

                    PrintSSaverStatus(" EnableButton_Click");
                }
            }
        }

        private string GetScreenSaverStatusMessage()
        {
            string message = $"Screen Saver is: \"{{0}}\", \"{{1}}\", timeout: \"{{2}}\"  {DateTime.UtcNow}";
            message = String.Format(message,
                NativeMethods.IsScreenSaverActive ? "active" : "inactive",
                NativeMethods.IsScreenSaverSecure ? "secure" : "not secure",
                NativeMethods.ScreenSaverTimeout);
            return message;
        }
    }
}

There is still small utility missing which is WPF console:仍然缺少 WPF 控制台的小实用程序:

using System;
using System.IO;
using System.Text;
using System.Windows.Controls;

namespace ManageScreenSaver.MediaElementWpf
{
    public class TextBoxWriter : TextWriter
    {

        private TextBox _TextBox;
        private string _NewLine = "\n";

        public TextBoxWriter(TextBox target)
        {
            if (target == null)
                throw new ArgumentNullException(nameof(target));

            _TextBox = target;
        }

        public override Encoding Encoding => new UTF8Encoding(false);

        public override string NewLine { get => _NewLine; set => _NewLine = value; }

        public override void Write(string value)
        {
            _TextBox.Dispatcher.InvokeAsync(
                () => _TextBox.AppendText(value)
                );
        }

        public override void WriteLine(string value)
        {
            _TextBox.Dispatcher.InvokeAsync(
                () => _TextBox.AppendText(value + NewLine)
                );
        }
    }
}

Beware: this is not production ready code.注意:这不是生产就绪代码。 It is necessary to implement error handling, system and monitor power events handling, login and logout handling: workstation session start and end, in session screen saver configuration changes.有必要实现错误处理、系统和监视器电源事件处理、登录和注销处理:工作站会话开始和结束、会话屏幕保护程序配置更改。

This method has some limitations and will not work when connected via RDP to remote machine but will work when connected via console to Windows VM in Hyper-V.这种方法有一些限制,在通过 RDP 连接到远程机器时不起作用,但在通过控制台连接到 Hyper-V 中的 Windows VM 时会起作用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM