如何检测Windows系统是否支持唤醒定时器

我需要以编程方式检测我的电脑(Windows 7/8)是否支持唤醒计时器。 到目前为止我已经完成了以下工作:

Guid activePowerScheme = GetActivePowerSchemeGuid(); IntPtr ptrActiveGuid = IntPtr.Zero; uint buffSize = 0; uint res = PowerReadACValue(IntPtr.Zero, ref activePowerScheme, ref ApplicationConstants.SLEEPGUID, ref ApplicationConstants.WAKETIMERGUID, IntPtr.Zero, IntPtr.Zero, ref buffSize); if (res == 0) { IntPtr ptrName = IntPtr.Zero; try { ptrName = Marshal.AllocHGlobal((int)buffSize); res = PowerReadACValue(IntPtr.Zero, ref activePowerScheme, ref ApplicationConstants.SLEEPGUID, ref ApplicationConstants.WAKETIMERGUID, IntPtr.Zero, ptrName, ref buffSize); byte[] ba = new byte[buffSize]; Marshal.Copy(ptrName, ba, 0, (int)buffSize); int retVal = BitConverter.ToInt32(ba, 0); if (retVal == 0) { return true; } else { return false; } } catch(Exception exp) { Logger.LogException(exp); return false; } finally { if (ptrName != IntPtr.Zero) { Marshal.FreeHGlobal(ptrName); } } } return false; 

这在大多数情况下都是有效的,但是当我重置我的电源计划设置时,这并不能很好地工作(不一致)。 我也尝试了以下内容:

 Guid currentPowerSchemeGuid = GetActivePowerSchemeGuid(); RegistryKey currentPowerSchemeKey = Registry.LocalMachine.OpenSubKey(@"SYSTEM\CurrentControlSet\Control\Power\User\PowerSchemes\" + currentPowerSchemeGuid.ToString()); if (currentPowerSchemeKey != null) { RegistryKey sleepRegKey = currentPowerSchemeKey.OpenSubKey(ApplicationConstants.SLEEPGUID.ToString()); currentPowerSchemeKey.Close(); if (sleepRegKey != null) { RegistryKey wakeTimerRegKey = sleepRegey.OpenSubKey(ApplicationConstants.WAKETIMERGUID.ToString()); sleepRegKey.Close(); if (wakeTimerRegKey != null) { wakeTimerRegKey.Close(); currentPowerSchemeKey.Close(); return true; } else { currentPowerSchemeKey.Close(); return false; } } else { currentPowerSchemeKey.Close(); return false; } } else { return false; } 

这不能重置电源计划设置,唤醒计时器GUIDregistry项被清除。 如果我的系统支持唤醒定时器,是否有正确的方法可以检测?

根据arx,尝试了下面的代码,它的工作原理。

  public static bool IsWakeTimerSupported() { IntPtr timerHandle = CreateWaitableTimer(IntPtr.Zero, true, "Wait Timer 1"); uint retVal = GetLastError(); if (timerHandle != IntPtr.Zero) { CancelWaitableTimer(timerHandle); CloseHandle(timerHandle); timerHandle = IntPtr.Zero; } //SUCCESS if (retVal == 0) { return true; } else { return false; } } 

CancelWaitableTimer(timerHandle)可以被忽略,因为MSDN文档说使用CloseHandle。

编辑:

 public static bool IsWakeTimerSupported() { IntPtr timerHandle = CreateWaitableTimer(IntPtr.Zero, true, "Wait Timer 1"); long interval = 0; int retVal = 0; if (timerHandle != IntPtr.Zero) { SetWaitableTimer(timerHandle, ref interval, 0, IntPtr.Zero, IntPtr.Zero, true); retVal = Marshal.GetLastWin32Error(); WaitableTimer.CancelWaitableTimer(timerHandle); try { Win32.CloseHandle(timerHandle); } catch (Exception exp) { Logger.LogException(exp); } timerHandle = IntPtr.Zero; } //SUCCESS if (retVal == 0) { return true; } else { return false; } } 

根据这篇文章, http://blogs.msdn.com/b/adam_nathan/archive/2003/04/25/56643.aspx我们不应该通过PInvoke使用GetLastError。

使用powrprof.dll库为我工作:

 using System; using System.ComponentModel; using System.Runtime.InteropServices; namespace Namespace { public static class PowerOptions { // src: https://msdn.microsoft.com/en-us/library/windows/desktop/hh448380%28v=vs.85%29.aspx private readonly static Guid HIGH_PERFORMANCE = new Guid("8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c"); // aka MIN_POWER_SAVINGS private readonly static Guid BALANCED = new Guid("381b4222-f694-41f0-9685-ff5bb260df2e"); // aka TYPICAL_POWER_SAVINGS private readonly static Guid POWER_SAVER = new Guid("a1841308-3541-4fab-bc81-f71556f20b4a"); // aka MAX_POWER_SAVINGS private readonly static Guid ACDC_POWER_SOURCE = new Guid("5d3e9a59-e9D5-4b00-a6bd-ff34ff516548"); private readonly static Guid SLEEP_SUBCATEGORY = new Guid("238C9FA8-0AAD-41ED-83F4-97BE242C8F20"); private readonly static Guid WAKE_TIMERS = new Guid("bd3b718a-0680-4d9d-8ab2-e1d2b4ac806d"); public static String GetCurrentPowerPlanFriendlyName() { IntPtr ptrActiveGuid = IntPtr.Zero; int ret = PowerGetActiveScheme(IntPtr.Zero, ref ptrActiveGuid); if (ret == 0) { uint buffSize = 0; ret = PowerReadFriendlyName(IntPtr.Zero, ptrActiveGuid, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, ref buffSize); if (ret == 0) { if (buffSize == 0) return ""; IntPtr ptrName = Marshal.AllocHGlobal((int) buffSize); ret = PowerReadFriendlyName(IntPtr.Zero, ptrActiveGuid, IntPtr.Zero, IntPtr.Zero, ptrName, ref buffSize); if (ret == 0) { String name = Marshal.PtrToStringUni(ptrName); Marshal.FreeHGlobal(ptrName); return name; } Marshal.FreeHGlobal(ptrName); } } throw new Win32Exception(ret, "GetCurrentPowerPlanFriendlyName"); } public static PowerStatus GetPowerStatus() { PowerStatus ps = new PowerStatus(); if (!GetSystemPowerStatus(ref ps)) throw new Win32Exception(Marshal.GetLastWin32Error(), "GetPowerStatus"); return ps; } public static bool GetWakeTimersEnabled(PowerSource powerSource = PowerSource.Current, PowerPlan powerPlan = PowerPlan.Current) { int ret = 0; if (powerSource == PowerSource.Current) { PowerStatus ps = GetPowerStatus(); if (ps.ACLineStatus == PowerLineStatus.Online) powerSource = PowerSource.PluggedIn; else powerSource = PowerSource.OnBattery; } if (ret == 0) { if (powerPlan == PowerPlan.Current) { IntPtr ptrPowerPlan = IntPtr.Zero; ret = PowerGetActiveScheme(IntPtr.Zero, ref ptrPowerPlan); if (ret == 0) { uint value = 0; if (powerSource == PowerSource.PluggedIn) ret = PowerReadACValueIndex(IntPtr.Zero, ptrPowerPlan, SLEEP_SUBCATEGORY, WAKE_TIMERS, ref value); else ret = PowerReadDCValueIndex(IntPtr.Zero, ptrPowerPlan, SLEEP_SUBCATEGORY, WAKE_TIMERS, ref value); if (ret == 0) { return (value == 1); } } } else { Guid guid = GetGuid(powerPlan); uint value = 0; if (powerSource == PowerSource.PluggedIn) ret = PowerReadACValueIndex(IntPtr.Zero, guid, SLEEP_SUBCATEGORY, WAKE_TIMERS, ref value); else ret = PowerReadDCValueIndex(IntPtr.Zero, guid, SLEEP_SUBCATEGORY, WAKE_TIMERS, ref value); if (ret == 0) { return (value == 1); } } } throw new Win32Exception(ret, "GetWakeTimersEnabled"); } public static Guid GetGuid(PowerPlan powerPlan) { if (powerPlan == PowerPlan.Balanced) return BALANCED; if (powerPlan == PowerPlan.HighPerformance) return HIGH_PERFORMANCE; if (powerPlan == PowerPlan.PowerSaver) return POWER_SAVER; throw new ArgumentException("Not a standard power plan: " + powerPlan); } [DllImport("powrprof.dll", SetLastError = true)] public static extern int PowerWriteACValueIndex(IntPtr RootPowerKey, Guid SchemeGuid, Guid SubGroupOfPowerSettingsGuid, Guid PowerSettingGuid, uint AcValueIndex); [DllImport("powrprof.dll", SetLastError = true)] private static extern int PowerReadACValueIndex(IntPtr RootPowerKey, IntPtr SchemeGuid, Guid SubGroupOfPowerSettingsGuid, Guid PowerSettingGuid, ref uint AcValueIndex); [DllImport("powrprof.dll", SetLastError = true)] private static extern int PowerReadACValueIndex(IntPtr RootPowerKey, Guid SchemeGuid, Guid SubGroupOfPowerSettingsGuid, Guid PowerSettingGuid, ref uint AcValueIndex); [DllImport("powrprof.dll", SetLastError = true)] private static extern int PowerReadDCValueIndex(IntPtr RootPowerKey, IntPtr SchemeGuid, Guid SubGroupOfPowerSettingsGuid, Guid PowerSettingGuid, ref uint AcValueIndex); [DllImport("powrprof.dll", SetLastError = true)] private static extern int PowerReadDCValueIndex(IntPtr RootPowerKey, Guid SchemeGuid, Guid SubGroupOfPowerSettingsGuid, Guid PowerSettingGuid, ref uint AcValueIndex); [DllImport("powrprof.dll", SetLastError = true)] private static extern int PowerGetActiveScheme(IntPtr UserRootPowerKey, ref IntPtr ActivePolicyGuid); [DllImport("powrprof.dll", SetLastError = true)] private static extern int PowerReadFriendlyName(IntPtr RootPowerKey, IntPtr SchemeGuid, IntPtr SubGroupOfPowerSettingsGuid, IntPtr PowerSettingGuid, IntPtr Buffer, ref uint BufferSize); [DllImport("kernel32.dll", SetLastError = true)] private static extern bool GetSystemPowerStatus(ref PowerStatus lpSystemPowerStatus); } public enum PowerPlan { Current, HighPerformance, Balanced, PowerSaver, } public enum PowerSource { Current, OnBattery, PluggedIn } public struct PowerStatus { ///<summary>The AC power status.</summary> public PowerLineStatus ACLineStatus; ///<summary>The battery charge status.</summary> public PowerChargeStatus BatteryFlag; ///<summary>Returns a value between [0 to 100] or 255 if unknown.</summary> public byte BatteryLifePercent; ///<summary>Returns a value that indicates if the system is currently conserving power.</summary> public PowerSaveStatus SystemStatusFlag; ///<summary>Number of seconds of battery life remaining, or -1 if unknown.</summary> public int BatteryLifeTime; ///<summary>Number of seconds of batter life on a full charge, or -1 if unknown.</summary> public int BatteryFullLifeTime; } public enum PowerLineStatus : byte { Offline = 0, Online = 1, Unknown = 255, } [Flags] public enum PowerChargeStatus : byte { High = 1, Low = 2, Critical = 4, Charging = 8, NoBattery = 128, Unknown = 255, } public enum PowerSaveStatus : byte { Off = 0, On = 1, } }