我需要以编程方式检测我的计算机(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注册表项被清除。有什么正确的方法可以检测我的系统是否支持唤醒计时器?

最佳答案

根据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;
        }
    }

由于MSDN文档说要使用CloseHandle,可以忽略CancelWaitableTimer(timerHandle)。

编辑:
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。

10-08 07:01