Click here to Skip to main content
Click here to Skip to main content

Wake the PC from standby or hibernation

By , 4 Oct 2010
 

Introduction

Sometimes, it might be useful to automatically turn on the PC at a certain time. To do this, we use a little trick: usually, a computer is not capable of igniting itself but is able to recover from standby or hibernation (if the hardware is capable of it).

Background

I structured the code on a base found on the internet, which is the heart of the code. Then I applied various improvements, and I made it all easily usable. Let's see how it works.

CreateWaitableTimer and SetWaitableTimer are our Windows API functions. Why? Because the Windows timer is able to resume the system, if used properly. The declaration is:

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

[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetWaitableTimer(SafeWaitHandle hTimer, 
                                            [In] ref long pDueTime, 
                                                      int lPeriod,
                                                   IntPtr pfnCompletionRoutine, 
                                                   IntPtr lpArgToCompletionRoutine, 
                                                     bool fResume);

We need to provide a date and a time, but SetWaitableTimer asks for a long integer value... DateTime.ToFileTime() is our lucky function.

This is the main code of the program:

long waketime = (long)e.Argument;

using (SafeWaitHandle handle = 
         CreateWaitableTimer(IntPtr.Zero, true, 
         this.GetType().Assembly.GetName().Name.ToString() + "Timer"))
{
    if (SetWaitableTimer(handle, ref waketime, 0, 
                         IntPtr.Zero, IntPtr.Zero, true))
    {
        using (EventWaitHandle wh = new EventWaitHandle(false, 
                                             EventResetMode.AutoReset))
        {
            wh.SafeWaitHandle = handle;
            wh.WaitOne();
        }
    }
    else
    {
        throw new Win32Exception(Marshal.GetLastWin32Error());
    }
}

Why is there a "e.Argument"?

long waketime = (long)e.Argument;

It's simple. This block of code pauses the execution of the thread until the timer does not reach the "wake time" value:

using (EventWaitHandle wh = new EventWaitHandle(false, 
                                EventResetMode.AutoReset))
{
    wh.SafeWaitHandle = handle;
    wh.WaitOne();
}

and this is not what we want. So, I inserted the block in a separate thread, controlled by a BackgrondWorker class.

I needed to create a class for easy re-use, so I decided to add an event: "Woken". Let's see how it works:

public event EventHandler Woken;

void bgWorker_RunWorkerCompleted(object sender, 
              RunWorkerCompletedEventArgs e)
{
    if (Woken != null)
    {
        Woken(this, new EventArgs());
    }
}

Very simple. Finally, this is the complete class:

using System;
using System.Text;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
using System.ComponentModel;
using System.Threading;

namespace WakeUPTimer
{
    class WakeUP
    {
        [DllImport("kernel32.dll")]
        public static extern SafeWaitHandle CreateWaitableTimer(IntPtr lpTimerAttributes, 
                                                                  bool bManualReset,
                                                                string lpTimerName);

        [DllImport("kernel32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool SetWaitableTimer(SafeWaitHandle hTimer, 
                                                    [In] ref long pDueTime, 
                                                              int lPeriod,
                                                           IntPtr pfnCompletionRoutine, 
                                                           IntPtr lpArgToCompletionRoutine, 
                                                             bool fResume);

        public event EventHandler Woken;

        private BackgroundWorker bgWorker = new BackgroundWorker();

        public WakeUP()
        {
            bgWorker.DoWork += new DoWorkEventHandler(bgWorker_DoWork);
            bgWorker.RunWorkerCompleted += 
              new RunWorkerCompletedEventHandler(bgWorker_RunWorkerCompleted);
        }

        public void SetWakeUpTime(DateTime time)
        {
            bgWorker.RunWorkerAsync(time.ToFileTime());
        }

        void bgWorker_RunWorkerCompleted(object sender, 
                      RunWorkerCompletedEventArgs e)
        {
            if (Woken != null)
            {
                Woken(this, new EventArgs());
            }
        }

        private void bgWorker_DoWork(object sender, DoWorkEventArgs e) 
        {
            long waketime = (long)e.Argument;

            using (SafeWaitHandle handle = 
                      CreateWaitableTimer(IntPtr.Zero, true, 
                      this.GetType().Assembly.GetName().Name.ToString() + "Timer"))
            {
                if (SetWaitableTimer(handle, ref waketime, 0, 
                                       IntPtr.Zero, IntPtr.Zero, true))
                {
                    using (EventWaitHandle wh = new EventWaitHandle(false, 
                                                           EventResetMode.AutoReset))
                    {
                        wh.SafeWaitHandle = handle;
                        wh.WaitOne();
                    }
                }
                else
                {
                    throw new Win32Exception(Marshal.GetLastWin32Error());
                }
            }
        }

    }
}

Using the Code

If we have a Button and a DateTimePicker on a form, we can write something like this:

private void button1_Click(object sender, EventArgs e)
{
    WakeUP wup = new WakeUP();
    wup.Woken += WakeUP_Woken;
    wup.SetWakeUpTime(dateTimePicker1.Value);
}

private void WakeUP_Woken(object sender, EventArgs e)
{
    // Do something 
}

And to suspend the system:

Application.SetSuspendState(PowerState.Suspend, false, false);

Remember: the last parameter, disableWakeEvent, must be false.

Troubleshooting

If the software doesn't work, it does not necessarily mean that your hardware doesn't support it. It's possible that some Windows settings prevent the awakening of the system. To make sure that the settings are correct, check that:

  • In "Control Panel > Power Options > Change Plan Settings > Change Advanced Power Settings > Sleep > Allow Wake Timers", all items are enabled.
  • If there is no password set on your Windows account, make sure that in "Control Panel > Power Options > Change Plan Settings > Change Advanced Power Settings > Brad / Additional Settings > Require a password on wakeup", all items are disabled (thanks nanfang).

Points of Interest

I used BackgroundWorker for a simple reason: the code in the Woken event must be in the same thread of the user interface for easy access to controls. With standard thread management, it's not easy to do that.

History

  • v1.0 - 2009/12/31 - Initial release.
  • v1.1 - 2010/10/03 - Fixed a bug and updated article (troubleshooting section).

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
Hint: For improved responsiveness ensure Javascript is enabled and choose 'Normal' from the Layout dropdown and hit 'Update'.
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionCode works, but monitor does not come ongroupPuWii21-May-13 21:12 
AnswerUpdate: Code works, but monitor does not come ongroupPuWii26-May-13 20:12 
GeneralMy vote of 5memberDeveshdevil8-Apr-13 0:39 
Questionit does't work well like this.memberlsf_20085-Nov-12 20:15 
QuestionCould you code it using vc++? thanks!memberlsf_20084-Nov-12 15:41 
Questionhow to make it wakeup daily instead of specified date?memberlordrt19-Aug-12 22:01 
QuestionFuture dates won't workmemberChrisPKnight21-Jun-12 6:14 
AnswerRe: Future dates won't workmemberDaniele Di Sarli21-Jun-12 11:19 
QuestionMy vote of 5 - Now I don't have to turn the server on in the morningmemberenhzflep16-Jun-12 20:49 
QuestionDon't wake up [modified]memberchenwangfen13-Nov-11 15:55 
AnswerRe: Don't wake upmemberDaniele Di Sarli13-Nov-11 19:42 
GeneralRe: Don't wake up [modified]memberchenwangfen14-Nov-11 15:43 
GeneralRe: Don't wake upmemberDaniele Di Sarli17-Nov-11 23:34 
GeneralMy vote of 5memberKanasz Robert10-Nov-11 23:41 
GeneralWorks GreatmemberPrasad_MCA15-Aug-11 7:28 
GeneralThe BackgroundWorker is busymemberhnldp2sh10-Mar-11 15:34 
GeneralRe: The BackgroundWorker is busymemberDaniele Di Sarli11-Mar-11 4:50 
GeneralWorks very well with standby and hibernate [modified]membergauravkale22-Feb-11 4:00 
GeneralRe: Works very well with standby and hibernatememberDaniele Di Sarli22-Feb-11 8:19 
GeneralScreen stays blackmemberneojudgment18-Jan-11 5:28 
GeneralRe: Screen stays blackmemberDaniele Di Sarli18-Jan-11 5:38 
GeneralRe: Screen stays blackmemberDaniele Di Sarli18-Jan-11 5:43 
... in the meanwhile, could you try this?
GeneralRe: Screen stays blackmemberneojudgment18-Jan-11 6:03 
GeneralRe: Screen stays blackmemberDaniele Di Sarli18-Jan-11 6:56 
GeneralRe: Screen stays blackmemberneojudgment27-Jan-11 10:32 
GeneralRe: Screen stays blackmemberDaniele Di Sarli27-Jan-11 10:53 
GeneralRe: Screen stays blackmemberSi.Jinmin26-Apr-12 20:34 
QuestionI want to write an event when the machine wakes up. How to go about itmemberdigvijay_nath11-Oct-10 17:16 
AnswerRe: I want to write an event when the machine wakes up. How to go about it [modified]memberKarthik. A11-Oct-10 18:48 
GeneralIt works on Windows Vista Ultimate x64memberhswear33-Oct-10 8:40 
GeneralRe: It works on Windows Vista Ultimate x64memberDaniele Di Sarli3-Oct-10 10:06 
AnswerRe: It works on Windows Vista Ultimate x64memberdigvijay_nath11-Oct-10 17:19 
GeneralRe: It works on Windows Vista Ultimate x64memberDaniele Di Sarli12-Oct-10 5:23 
GeneralExcellent!!!memberShanthi Diana22-Aug-10 9:32 
GeneralRe: Excellent!!!memberDaniele Di Sarli23-Aug-10 3:38 
GeneralIt doesn't work for memembernanfang25-Jul-10 9:45 
GeneralRe: It doesn't work for mememberDaniele Di Sarli25-Jul-10 10:07 
GeneralRe: It doesn't work for memembernanfang26-Jul-10 17:47 
GeneralRe: It doesn't work for mememberDaniele Di Sarli26-Jul-10 23:35 
GeneralRe: It doesn't work for mememberOscar Londono3-Oct-10 3:13 
GeneralHimemberfanan_boy13-May-10 13:12 
Generalhimemberfanan_boy12-May-10 5:20 
GeneralRe: himemberDaniele Di Sarli12-May-10 5:59 
Generalit's simple,but very useful!memberhackcat10-Jan-10 14:21 
GeneralThanks a lot !!! \o/membersasusk331-Dec-09 13:54 
GeneralRe: Thanks a lot !!! \o/memberDaniele Di Sarli31-Dec-09 23:57 
General:omemberNightJammer31-Dec-09 11:13 
GeneralRe: :omemberDaniele Di Sarli31-Dec-09 23:59 
GeneralRe: :omemberDave Cross4-Oct-10 11:19 
GeneralRe: :omemberNightJammer4-Oct-10 17:49 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web04 | 2.6.130617.1 | Last Updated 4 Oct 2010
Article Copyright 2009 by Daniele Di Sarli
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid