我需要以编程方式检测我的计算机(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;
}
这对重置电源计划设置无效,唤醒定时器GUID注册表项被清除。有没有正确的方法可以检测我的系统是否支持唤醒定时器?
答案 0 :(得分:0)
根据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。
答案 1 :(得分:0)
使用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,
}
}