Click here to Skip to main content
Licence CPOL
First Posted 31 Dec 2009
Views 31,047
Downloads 477
Bookmarked 68 times

Wake the PC from standby or hibernation

By | 4 Oct 2010 | Article
How to wake up the PC at a certain time.

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

Daniele Di Sarli



Italy Italy

Member



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

 
You must Sign In to use this message board. (secure sign-in)
 
Search this forum  
 FAQ
    Noise  Layout  Per page   
  Refresh
QuestionDon't wake up [modified] Pinmemberchenwangfen15:55 13 Nov '11  
AnswerRe: Don't wake up PinmemberDaniele Di Sarli19:42 13 Nov '11  
GeneralRe: Don't wake up [modified] Pinmemberchenwangfen15:43 14 Nov '11  
GeneralRe: Don't wake up PinmemberDaniele Di Sarli23:34 17 Nov '11  
GeneralMy vote of 5 PinmemberKanasz Robert23:41 10 Nov '11  
GeneralWorks Great PinmemberPrasad_MCA7:28 15 Aug '11  
GeneralThe BackgroundWorker is busy Pinmemberhnldp2sh15:34 10 Mar '11  
GeneralRe: The BackgroundWorker is busy PinmemberDaniele Di Sarli4:50 11 Mar '11  
GeneralWorks very well with standby and hibernate [modified] Pinmembergauravkale4:00 22 Feb '11  
GeneralRe: Works very well with standby and hibernate PinmemberDaniele Di Sarli8:19 22 Feb '11  
GeneralScreen stays black Pinmemberneojudgment5:28 18 Jan '11  
GeneralRe: Screen stays black PinmemberDaniele Di Sarli5:38 18 Jan '11  
GeneralRe: Screen stays black PinmemberDaniele Di Sarli5:43 18 Jan '11  
GeneralRe: Screen stays black Pinmemberneojudgment6:03 18 Jan '11  
GeneralRe: Screen stays black PinmemberDaniele Di Sarli6:56 18 Jan '11  
GeneralRe: Screen stays black Pinmemberneojudgment10:32 27 Jan '11  
GeneralRe: Screen stays black PinmemberDaniele Di Sarli10:53 27 Jan '11  
GeneralRe: Screen stays black PinmemberSi.Jinmin20:34 26 Apr '12  
QuestionI want to write an event when the machine wakes up. How to go about it Pinmemberdigvijay_nath17:16 11 Oct '10  
AnswerRe: I want to write an event when the machine wakes up. How to go about it [modified] PinmemberKarthik. A18:48 11 Oct '10  
GeneralIt works on Windows Vista Ultimate x64 Pinmemberhswear38:40 3 Oct '10  
GeneralRe: It works on Windows Vista Ultimate x64 PinmemberDaniele Di Sarli10:06 3 Oct '10  
AnswerRe: It works on Windows Vista Ultimate x64 Pinmemberdigvijay_nath17:19 11 Oct '10  
GeneralRe: It works on Windows Vista Ultimate x64 PinmemberDaniele Di Sarli5:23 12 Oct '10  
GeneralExcellent!!! PinmemberShanthi Diana9:32 22 Aug '10  

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

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

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