回答は、2つのソリューションが含まれていますUWP DisplayRequest
クラスに基づいて(i)は、(ⅱ)に基づいて、より一般的なカスタムクラスScreenSaverManager
です。
1. UWP DisplayRequest
クラス
Windowsのスクリーンセーバーの停止を要求する直接法を提供し、正常に呼び出すと、スクリーンセーバーが、すなわちメディアの再生中に起因する利用者の非アクティブに起動しないことが保証されます。再度スクリーンセーバを有効にする方法では逆も可能です。どちらの方法もWindows 10(UWP Runtime)で利用でき、Windows.System.Display.DisplayRequest
クラスからアクセスできます。 WPFデスクトップアプリケーションでUWPアプリケーションの外部で使用する方法の例を以下に示します。
コードを使用して作業する前に、テンプレートからのVisual Studioで作成した標準のWPFアプリケーションに次の参照を追加する必要がある:ディレクトリから(I)Windows.winmd
:ディレクトリからC:\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 )。
再生中にスクリーンセーバを一時停止または有効にするには、再生イベントを関連するメソッドに開始および停止させます。
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>
のWindows 10 UWP APIにアクセスするために、アセンブリを参照する上でもう一つの命令
は
UwpDesktop NuGet packageのWebページ上で見つけることができます。 UwpDesktopパッケージ自体は、少なくとも最後の2つのWindows 10 Creatorsの更新期間中は維持されていないようですが、10.0.14393 APIを対象とする場合はまだ有効です。
C/C++コードからこのメソッドを使用する方法の例については
はSystem.Windows.Controls.MediaElement
コントロールの文書化されていない動作に関連した質問の一部に挑むSDL Library
2.カスタムScreenSaverManager
クラス
のレポを見ますメディア再生中はスクリーンセーバを一時停止します。ユーザーが映画を見ているという観点から、スクリーンセーバーの起動を防ぐことは良い方法であるという事実にもかかわらず、望ましくないアプリケーションがあります。セキュリティ上の理由やメディアの再生が最も重要なアプリケーション機能ではないため、スクリーンセーバーやワークステーションのロックアウトを強制的に無効にすることは良い方法ではありません。 Microsoftは、この機能を制御するために使用できるパブリックプロパティを提供する必要があります。
ハッキングを避けるため、私はWin32および.NET/WPFパブリックAPIのみを使用して問題を解決しようとしました。最も簡単で最も効果的なソリューションは、OSの機能を複製し、オンデマンドのオリジナルのスクリーンセーバの動作(自動スクリーンセーバと自動ログオフなど)を適用する独自のScreenSaverManager
を作成することに基づいています。最初に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);
}
}
}
}
相互運用方法は、別のクラス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,
}
}
最後に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;
}
}
}
がまだ小さいユーティリティが見つからないありされています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)
);
}
}
}
注意:これは生産準備完了コードではありません。エラー処理、システムおよびパワーイベントの処理、ログイン、ログアウトの処理を実装する必要があります。ワークステーションセッションの開始と終了、セッションスクリーンセーバーの設定変更。
この方法にはいくつかの制限があり、RDP経由でリモートマシンに接続すると機能しませんが、コンソール経由でHyper-VのWindows VMに接続すると機能します。
ハードな問題は、比較的簡単な方法で解決されています。新しい編集とコードリストを見てください:) –