Почему мой компьютер с Windows 10 не просыпается после вызова SetWaitableTimer()?
У меня есть два компьютера с Windows 10, на которых установлено обновление Fall Creators, со всеми последними установленными исправлениями. Один просыпается из сна после того, как таймер установлен через 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). Интересно, что задание не разбудило компьютер.
1 ответ
В процессе обновления для Fall Creators Update была изменена ключевая настройка управления питанием.
В разделе "Дополнительные параметры питания" -> "Режим сна" -> "Разрешить таймеры пробуждения" предыдущий параметр "Включить" был изменен на "Только важные таймеры пробуждения". "Только важные таймеры пробуждения" была введена сравнительно недавно.
Это изменение привело к тому, что система, которая не проснулась, проигнорировала события пробуждения, запланированные в программном обеспечении. По сути, он предназначен для того, чтобы учитывать только пробуждения операционной системы.
Возврат значения "Включено" решило проблему.