15

What's the best way to programmatically cause a Windows XP (or above) machine to wake up at a specific time. (Ideally a lot like how Media Center can start up automatically to record a particular TV program)

I've got a Windows service (written in C#) and I'd like this service to be able to cause the machine it is hosted on to start up at predetermined times.

Are there any BIOS settings or prerequisites (eg. ACPI) that need to be configured for this to work correctly?

This machine would be using dialup or 3G wireless modem, so unfortunately it can't rely on Wake on LAN.

David Gardiner
  • 16,892
  • 20
  • 80
  • 117

4 Answers4

12

You can use waitable timers to wake from a suspend or hibernate state. From what I can find, it is not possible to programmatically wake from normal shut down mode (soft off/S5), in that case, you need to specify a WakeOnRTC alarm in BIOS. To use waitable timers from C#, you need pInvoke. The import declarations are:

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);

You can use those functions in the following way:

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

You can then cancel the waitable timer with CancelWaitableTimer, using the returned handle as an argument.

Your program can hibernate and sleep using 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);
}

Your system may not allow programs to let the computer enter hibernation. You can call the following method to allow hibernation:

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();
}
Boris
  • 5,094
  • 4
  • 45
  • 71
  • That looks like it might be it. I found another example of this here - http://www.codeproject.com/Articles/49798/Wake-the-PC-from-standby-or-hibernation – David Gardiner Feb 06 '12 at 00:54
  • I followed your code, The system can be successfully go to hibernate mode, but, It was not wake up again from hibernate mode at specified time. – Viswa Aug 10 '13 at 05:23
  • I haven't followed this actual code, but I can vouch that on decade-old hardware (with the BIOS options set (see below)), this Win32 API does work. I wrote a C# synch tool that worked a treat. – Luke Puplett Dec 02 '14 at 14:42
  • This code didn't work for me at first, but looking at http://www.codeproject.com/Articles/49798/Wake-the-PC-from-standby-or-hibernation I managed to fix the problem by changing only ToFileTimeUtc to ToFileTime. Remember to enable wake timers from the power options. @Viswa a computer cannot wake up from hibernation, only from sleep mode. – Bonnev Jul 21 '15 at 00:36
4

The task scheduler program in Win7, taskschd.msc (and I beleive XP as well) can be set to wake the system on different triggers. Those triggers can be schedule, time, event, etc.

In at least Win7, you need to set "Allow Wake Timers" to 'Enabled' for this to work. This setting is found under...

--> Control Panel\Hardware and Sound\Power Options
click - "Edit Plan Settings"
click - "Change advanced power setting"
expand - "Sleep"
Expand - "Allow Wake timers"

etropic
  • 129
  • 8
  • I think this is getting closer to the real answer. As I want to do this programmatically, I want to know what API to use to set a 'wake timer' – David Gardiner Sep 22 '10 at 00:44
  • Well, task scheduler in Win7 is different from the one in XP. For XP you can use the at command (http://support.microsoft.com/kb/313565) or the Task Scheduler 1.0 API (http://msdn.microsoft.com/en-us/library/aa383579(VS.85).aspx). You have a wrapper in http://www.codeproject.com/KB/cs/tsnewlib.aspx. While in Windows 7 you have the new 2.0 API (http://msdn.microsoft.com/en-us/library/aa384138(VS.85).aspx) – jmservera Sep 22 '10 at 09:35
2

Your best bet is using Wake on LAN capability. This will require another machine to send a packet of a special kind to wake your machine up.

This will not be helpful if your machine is not connected to the network or you for some reason don't wasnt to move this logic onto another machine. But it's useful for some configurations where you have multiple machines and want to wake them up programmatically.

sharptooth
  • 167,383
  • 100
  • 513
  • 979
0

Some machines have a BIOS alarm clock that can be set to wake up the computer at a certain hour. It should be possible to program this clock, but I don't know the specific details.

Edit: I found this program that should let you set the time. It's in C, under Linux, but maybe it can give you some hints.

A warning though: before trying anything that changes the BIOS settings directly be sure to write down every setting from BIOS screens, because in case of an error the BIOS might revert to factory default and you might need to set it up again as it was.

rslite
  • 81,705
  • 4
  • 44
  • 47