I need to programmatically detect whether my computer (Windows 7 / 8) supports wake timers. So far I have done the following:
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;
This works most of the time, but when I reset my power plan settings, this doesn't work well (inconsistent). I also tried the following:
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;
}
This doesn't work on reset of power plan settings, the wake timer GUID registry key gets cleared. Is there a proper way I can detect if my system supports wake timers?
According to arx, tried the following code and it works.
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;
}
}
The CancelWaitableTimer(timerHandle) can be ignored as the MSDN documentation says to use CloseHandle.
EDIT:
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;
}
}
According to this article, http://blogs.msdn.com/b/adam_nathan/archive/2003/04/25/56643.aspx we shoud never use GetLastError through PInvoke.