安排机器自动唤醒

15

如何以编程方式在特定时间唤醒Windows XP(或更高版本)计算机最佳方法?(最好像Media Center那样自动启动以录制特定的电视节目)

我有一个Windows服务(用C#编写),我希望该服务能够在预定的时间唤醒托管它的计算机。

是否需要配置任何BIOS设置或先决条件(例如ACPI)才能使其正常工作?

由于此计算机将使用拨号或3G无线调制解调器,因此不幸的是,它不能依赖Wake on LAN。


也许http://serverfault.com上的人会知道。 - jmservera
4个回答

12

你可以使用可等待计时器来从挂起或休眠状态唤醒。据我所知,无法以编程方式从正常关闭模式(软关机/S5)中唤醒,在这种情况下,您需要在BIOS中指定WakeOnRTC闹钟。要从C#中使用可等待计时器,您需要使用pInvoke。导入声明如下:

public delegate void TimerCompleteDelegate();

[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr CreateWaitableTimer(IntPtr lpTimerAttributes, bool bManualReset, string lpTimerName);

[DllImport("kernel32.dll", SetLastError = true)]
static extern bool SetWaitableTimer(IntPtr hTimer, [In] ref long pDueTime, int lPeriod, TimerCompleteDelegate pfnCompletionRoutine, IntPtr pArgToCompletionRoutine, bool fResume);

[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool CancelWaitableTimer(IntPtr hTimer);

您可以按照以下方式使用这些函数:

public static IntPtr SetWakeAt(DateTime dt)
{
    TimerCompleteDelegate timerComplete = null;

    // read the manual for SetWaitableTimer to understand how this number is interpreted.
    long interval = dt.ToFileTimeUtc(); 
    IntPtr handle = CreateWaitableTimer(IntPtr.Zero, true, "WaitableTimer");
    SetWaitableTimer(handle, ref interval, 0, timerComplete, IntPtr.Zero, true);
    return handle;
}

您可以使用返回的句柄作为参数,使用CancelWaitableTimer取消可等待定时器。

您的程序可以使用pInvoke进行休眠和睡眠:

[DllImport("powrprof.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool SetSuspendState(bool hibernate, bool forceCritical, bool disableWakeEvent);

public static bool Hibernate()
{
    return SetSuspendState(true, false, false);
}

public static bool Sleep()
{
    return SetSuspendState(false, false, false);
}

您的系统可能不允许程序使计算机进入休眠状态。您可以调用以下方法来允许休眠:

public static bool EnableHibernate()
{
    Process p = new Process();
    p.StartInfo.FileName = "powercfg.exe";
    p.StartInfo.CreateNoWindow = true;
    p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
    p.StartInfo.Arguments = "/hibernate on"; // this might be different in other locales
    return p.Start();
}

那看起来可能是它。我在这里找到了另一个示例 - http://www.codeproject.com/Articles/49798/Wake-the-PC-from-standby-or-hibernation - David Gardiner
我按照你的代码操作,系统可以成功进入休眠模式,但是在指定时间无法从休眠模式中唤醒。 - Viswa
我没有跟进这个实际的代码,但我可以保证,在十年前的硬件上(设置了BIOS选项(见下文)),这个Win32 API确实可以工作。我写了一个C#同步工具,效果很好。 - Luke Puplett
这段代码一开始对我来说并没有起作用,但是在查看了http://www.codeproject.com/Articles/49798/Wake-the-PC-from-standby-or-hibernation之后,我仅仅通过将ToFileTimeUtc更改为ToFileTime就解决了问题。记得从电源选项中启用唤醒计时器。@Viswa 电脑只能从睡眠模式中唤醒,而不能从休眠模式中唤醒。 - Bonnev

4
Win7中的任务计划程序,taskschd.msc(我相信XP也是如此),可以根据不同的触发器唤醒系统。这些触发器可以是计划、时间、事件等。
在至少Win7中,您需要将“允许唤醒计时器”设置为“已启用”才能使其正常工作。此设置位于...
--> 控制面板\硬件和声音\电源选项 点击 - “更改计划设置” 点击 - “更改高级电源设置” 展开 - “睡眠” 展开 - “允许唤醒计时器”

我认为这已经接近真正的答案了。由于我想以编程方式实现这个功能,我想知道要使用哪个API来设置“唤醒定时器”。 - David Gardiner
Windows 7中的任务计划程序与XP中的不同。对于XP,您可以使用at命令 (http://support.microsoft.com/kb/313565) 或任务计划程序1.0 API (http://msdn.microsoft.com/en-us/library/aa383579(VS.85).aspx)。您可以在 http://www.codeproject.com/KB/cs/tsnewlib.aspx 中找到一个包装器。而在Windows 7中,您有新的2.0 API (http://msdn.microsoft.com/en-us/library/aa384138(VS.85).aspx)。 - jmservera

2
你最好的选择是使用“远程唤醒”功能。这将需要另一台机器发送一个特殊类型的数据包来唤醒你的机器。
如果你的机器没有连接到网络或出于某种原因不想将此逻辑移动到另一台机器上,则此方法将无效。但对于某些配置,例如你有多台机器并且希望以编程方式唤醒它们时,它非常有用。

0
一些机器有一个BIOS闹钟,可以设置在特定时间唤醒计算机。应该可以编程这个时钟,但我不知道具体细节。
编辑:我找到了这个程序,它应该可以让你设置时间。它是在Linux下用C编写的,但也许它可以给你一些提示。
警告:在尝试更改BIOS设置之前,请确保从BIOS屏幕上记录每个设置,因为如果出现错误,BIOS可能会恢复到出厂默认设置,您可能需要重新设置它。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接