为什么我的 Windows 10 PC 在调用 SetWaitableTimer() 后没有唤醒?
Why Isn't My Windows 10 PC Waking Up after a SetWaitableTimer() Call?
我有两台 Windows 10 PC,都是 运行 Fall Creators Update,安装了所有最新补丁。一个在通过 CreateWaitableTimer/SetWaitableTimer 设置定时器后从睡眠中醒来,另一个没有......这是一个问题,因为非唤醒的是我的 DVR,需要能够按需唤醒: ).
都没有启用休眠。
我在拒绝唤醒的系统上看不到任何异常事件。它只是不唤醒,除非我手动唤醒或向它发送局域网唤醒数据包。
这是我在两个系统上 运行 的 C# 测试代码:
public class Program
{
[ DllImport( "kernel32.dll" ) ]
private static extern SafeWaitHandle CreateWaitableTimer( IntPtr lpTimerAttributes, bool bManualReset,
string lpTimerName );
[ DllImport( "kernel32.dll", SetLastError = true ) ]
[ return : MarshalAs( UnmanagedType.Bool ) ]
private static extern bool SetWaitableTimer( SafeWaitHandle hTimer, [ In ] ref long pDueTime, int lPeriod,
IntPtr pfnCompletionRoutine, IntPtr lpArgToCompletionRoutine, bool fResume );
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool CancelWaitableTimer(IntPtr hTimer);
[DllImport("powrprof.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool SetSuspendState(bool hibernate, bool forceCritical, bool disableWakeEvent);
private static ILogger _logger;
private static bool Hibernate()
{
bool retVal = SetSuspendState(true, false, false);
_logger.Information(retVal
? $"Returning from hibernation at {DateTime.Now.ToLongTimeString()}"
: $"Failed to enter hibernation, error message was {Marshal.GetLastWin32Error()}");
return retVal;
}
private static bool Sleep()
{
bool retVal = SetSuspendState(false, false, false);
_logger.Information( retVal
? $"Returning from sleep at {DateTime.Now.ToLongTimeString()}"
: $"Failed to enter sleep, error message was {Marshal.GetLastWin32Error()}" );
return retVal;
}
private static void SetWakeTimer( int minutes, bool hibernate )
{
DateTime utc = DateTime.Now.AddMinutes( minutes );
long duetime = utc.ToFileTime();
using( SafeWaitHandle handle = CreateWaitableTimer( IntPtr.Zero, true, "SleepWakeTimerTest" ) )
{
if( SetWaitableTimer( handle, ref duetime, 0, IntPtr.Zero, IntPtr.Zero, true ) )
{
_logger.Information($"Timer set, will trigger at {utc.ToLongTimeString()}");
if ( hibernate ) Hibernate();
else Sleep();
}
else
Console.WriteLine($"CreateWaitableTimer failed, error message was {Marshal.GetLastWin32Error()}");
}
}
static void Main( string[] args )
{
_logger = new LoggerConfiguration()
.WriteTo.File( $"log-{DateTime.Now:yyyy-M-d-hhmmss}.txt" )
.CreateLogger();
_logger.Information("parsing command line arguments...");
var cmdLine = new FluentCommandLineParser();
int delay = 2;
bool hibernate = false;
cmdLine.Setup<int>( 'd', "delay" )
.Callback( x => delay = x )
.SetDefault( 2 )
.WithDescription( "wakeup delay, in minutes" );
cmdLine.Setup<bool>( 'h', "hibernate" )
.Callback( x => hibernate = x )
.SetDefault( false )
.WithDescription( "hibernate if flag set, otherwise sleep" );
SetWakeTimer( delay, hibernate );
}
}
非常感谢有关检查内容或采取哪些额外诊断步骤的建议。
附加信息
有人建议我尝试通过手动定义的计划任务(即使用 Task Scheduler 应用程序)唤醒计算机。有趣的是,任务并没有唤醒电脑。
在 Fall Creators Update 的升级过程中,一项关键的电源管理设置发生了变化。
在高级电源设置 -> 睡眠 -> 允许唤醒定时器下,之前的启用设置已更改为仅重要唤醒定时器。 "Important Wake Timers Only" 是最近引入的新设置。
此更改导致无法唤醒的系统忽略软件中安排的唤醒事件。基本上,它旨在仅允许操作系统唤醒。
将设置恢复为启用解决了问题。
我有两台 Windows 10 PC,都是 运行 Fall Creators Update,安装了所有最新补丁。一个在通过 CreateWaitableTimer/SetWaitableTimer 设置定时器后从睡眠中醒来,另一个没有......这是一个问题,因为非唤醒的是我的 DVR,需要能够按需唤醒: ).
都没有启用休眠。
我在拒绝唤醒的系统上看不到任何异常事件。它只是不唤醒,除非我手动唤醒或向它发送局域网唤醒数据包。
这是我在两个系统上 运行 的 C# 测试代码:
public class Program
{
[ DllImport( "kernel32.dll" ) ]
private static extern SafeWaitHandle CreateWaitableTimer( IntPtr lpTimerAttributes, bool bManualReset,
string lpTimerName );
[ DllImport( "kernel32.dll", SetLastError = true ) ]
[ return : MarshalAs( UnmanagedType.Bool ) ]
private static extern bool SetWaitableTimer( SafeWaitHandle hTimer, [ In ] ref long pDueTime, int lPeriod,
IntPtr pfnCompletionRoutine, IntPtr lpArgToCompletionRoutine, bool fResume );
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool CancelWaitableTimer(IntPtr hTimer);
[DllImport("powrprof.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool SetSuspendState(bool hibernate, bool forceCritical, bool disableWakeEvent);
private static ILogger _logger;
private static bool Hibernate()
{
bool retVal = SetSuspendState(true, false, false);
_logger.Information(retVal
? $"Returning from hibernation at {DateTime.Now.ToLongTimeString()}"
: $"Failed to enter hibernation, error message was {Marshal.GetLastWin32Error()}");
return retVal;
}
private static bool Sleep()
{
bool retVal = SetSuspendState(false, false, false);
_logger.Information( retVal
? $"Returning from sleep at {DateTime.Now.ToLongTimeString()}"
: $"Failed to enter sleep, error message was {Marshal.GetLastWin32Error()}" );
return retVal;
}
private static void SetWakeTimer( int minutes, bool hibernate )
{
DateTime utc = DateTime.Now.AddMinutes( minutes );
long duetime = utc.ToFileTime();
using( SafeWaitHandle handle = CreateWaitableTimer( IntPtr.Zero, true, "SleepWakeTimerTest" ) )
{
if( SetWaitableTimer( handle, ref duetime, 0, IntPtr.Zero, IntPtr.Zero, true ) )
{
_logger.Information($"Timer set, will trigger at {utc.ToLongTimeString()}");
if ( hibernate ) Hibernate();
else Sleep();
}
else
Console.WriteLine($"CreateWaitableTimer failed, error message was {Marshal.GetLastWin32Error()}");
}
}
static void Main( string[] args )
{
_logger = new LoggerConfiguration()
.WriteTo.File( $"log-{DateTime.Now:yyyy-M-d-hhmmss}.txt" )
.CreateLogger();
_logger.Information("parsing command line arguments...");
var cmdLine = new FluentCommandLineParser();
int delay = 2;
bool hibernate = false;
cmdLine.Setup<int>( 'd', "delay" )
.Callback( x => delay = x )
.SetDefault( 2 )
.WithDescription( "wakeup delay, in minutes" );
cmdLine.Setup<bool>( 'h', "hibernate" )
.Callback( x => hibernate = x )
.SetDefault( false )
.WithDescription( "hibernate if flag set, otherwise sleep" );
SetWakeTimer( delay, hibernate );
}
}
非常感谢有关检查内容或采取哪些额外诊断步骤的建议。
附加信息
有人建议我尝试通过手动定义的计划任务(即使用 Task Scheduler 应用程序)唤醒计算机。有趣的是,任务并没有唤醒电脑。
在 Fall Creators Update 的升级过程中,一项关键的电源管理设置发生了变化。
在高级电源设置 -> 睡眠 -> 允许唤醒定时器下,之前的启用设置已更改为仅重要唤醒定时器。 "Important Wake Timers Only" 是最近引入的新设置。
此更改导致无法唤醒的系统忽略软件中安排的唤醒事件。基本上,它旨在仅允许操作系统唤醒。
将设置恢复为启用解决了问题。