Click here to Skip to main content
13,195,821 members (52,826 online)
Click here to Skip to main content
Add your own
alternative version

Stats

104.1K views
3.3K downloads
118 bookmarked
Posted 31 Dec 2009

Wake the PC from standby or hibernation

, 3 Feb 2014
Rate this:
Please Sign up or sign in to vote.
How to automatically wake up the PC at some time in the future.

Introduction

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

Background

The code is mainly a wrapper around two system timer functions: CreateWaitableTimer and SetWaitableTimer. That's because the timer is able to resume the system, if told to. 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 the function that we'll use to convert date/times from managed to system representations. 

Take a look at the core of the program, where we call the two API functions: 

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

You can notice an "e.Argument" in the first line. It's there because the following block of code pauses the execution of the thread until the timer reaches the "wake time" value:

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

So, to avoid blocking the UI thread, we need to put that block of code into a separate thread, controlled by a BackgroundWorker object to which we'll pass the wake time as an argument. This is where "e.Argument" comes from.

I needed to create a class for easy re-use, so I decided to provide an event: "Woken". The event gets triggered as soon as the background thread exits:

public event EventHandler Woken;

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

So, to recap, this is the full 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);

Important note: the last parameter, disableWakeEvent, needs to be false.

Troubleshooting

If the software doesn't work, it doesn't necessarily mean that your hardware doesn't support it. It's possible that some Windows setting is preventing 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 a 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, that's not so trivial.

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)

Share

About the Author

No Biography provided

You may also be interested in...

Comments and Discussions

 
QuestionHow to turnon monitor at the time of wakeup. Pin
Member 118318764-Apr-16 20:01
memberMember 118318764-Apr-16 20:01 
GeneralMy vote of 5 Pin
csharpbd31-Mar-16 10:39
professionalcsharpbd31-Mar-16 10:39 
QuestionFor Windows 8 finally move the mouse to turn the screen on again. Pin
andrew douse20-Apr-15 21:39
memberandrew douse20-Apr-15 21:39 
QuestionCan you provide me with executable please? Pin
Member 20108973-Mar-15 20:10
memberMember 20108973-Mar-15 20:10 
QuestionFine!!!!!!! Pin
Volynsky Alex3-Feb-14 11:07
professionalVolynsky Alex3-Feb-14 11:07 
GeneralMy vote of 5 Pin
peteSJ3-Feb-14 8:50
memberpeteSJ3-Feb-14 8:50 
QuestionNice, dude! My vote of 5! Pin
Viktor Signaievskyi1-Feb-14 10:39
memberViktor Signaievskyi1-Feb-14 10:39 
BugSystem doesn't wake up Pin
suneth_ac31-Aug-13 22:23
membersuneth_ac31-Aug-13 22:23 
QuestionCode works, but monitor does not come on Pin
PuWii21-May-13 21:12
groupPuWii21-May-13 21:12 
Hi, Thanks for a beautifully simple solution.

I am using WINXP Pro SP2. The code works error-free but...
1. The monitor stays in standby mode and I need to use mouse/keyboard to wake it up
2. The Woken date/time is correctly displayed, which indicates that the system did wake up at the correct time.
3. I tried the SetExecutionSate solution given, but after I introduced that in the code, the computer did not wake up at all and I had to do a cold boot.

I don't know C#, but manage to read and understand C# code.

I have put the entire code here (in vb.net 2005) for others to use, and give me a pointer to the error (or better still, the solution itself Smile | :) )

Thanks in advance

This is the code for the Form:

Imports System
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.Data
Imports System.Drawing
Imports System.Text
Imports System.Windows.Forms
Public Class frmWakeUp
    Dim wup As MyWakeUpTimer.WakeUP
 
    Private Sub timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles timer1.Tick
        lblNow.Text = String.Format("Now: {0}", DateTime.Now.ToShortDateString() + " " + DateTime.Now.ToLongTimeString())
    End Sub
    Private Sub button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles button1.Click
        Dim wup As New MyWakeUpTimer.WakeUP()
        AddHandler wup.Woken, AddressOf WakeUP_Woken
        wup.SetWakeUpTime(DateTimePicker1.Value)
 
    End Sub
    Private Sub WakeUP_Woken(ByVal sender As Object, ByVal e As EventArgs)
        lblWoken.Text = String.Format("Woken: {0}", (DateTime.Now.ToShortDateString + (" " + DateTime.Now.ToLongTimeString)))
    End Sub
    Private Sub button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles button2.Click
        'Application.SetSuspendState(PowerState.Hibernate, false, false)
        Application.SetSuspendState(PowerState.Suspend, False, False)
    End Sub
 
End Class


This is the code for the Class

Imports System
Imports System.Text
Imports System.Runtime.InteropServices
Imports Microsoft.Win32.SafeHandles
Imports System.ComponentModel
Imports System.Threading
 
Class WakeUP
    'Public Enum EXECUTION_STATE As UInteger
    '    ES_CONTINUOUS = &H80000000L
    '    ES_DISPLAY_REQUIRED = &H2
    '    ES_SYSTEM_REQUIRED = &H1
    '    ES_AWAYMODE_REQUIRED = &H40
    'End Enum
 
    'Private Const VK_NONAME As Integer = &HFC
    'Private Const KEYEVENTF_SILENT As Byte = &H4
 
    '<DllImport("Kernel32.DLL", CharSet:=CharSet.Auto, SetLastError:=True)> _
    'Protected Shared Function SetThreadExecutionState(ByVal state As EXECUTION_STATE) As EXECUTION_STATE
    'End Function
 
    '<DllImport("user32.dll")> _
    'Private Shared Sub keybd_event(ByVal bVk As Byte, ByVal bScan As Byte, ByVal dwFlags As UInteger, _
    '                                ByVal dwExtraInfo As Integer)
    'End Sub
 
    <DllImport("kernel32.dll")> Private Shared Function CreateWaitableTimer( _
    ByVal lpTimerAttributes As IntPtr, _
    ByVal bManualReset As Boolean, _
    ByVal lpTimerName As String) As SafeWaitHandle 'IntPtr
    End Function
    'Public Declare Function CreateWaitableTimer Lib "kernel32.dll" (ByVal lpTimerAttributes As IntPtr, ByVal bManualReset As Boolean, ByVal lpTimerName As String) As SafeWaitHandle
 
    <DllImport("kernel32.dll")> Private Shared Function SetWaitableTimer( _
    ByVal hTimer As SafeWaitHandle, _
    ByRef pDueTime As Long, _
    ByVal lPeriod As Integer, _
    ByVal pfnCompletionRoutine As IntPtr, _
    ByVal lpArgToCompletionRoutine As IntPtr, _
    ByVal fResume As Boolean) As Boolean
    End Function
    'Public Declare Function SetWaitableTimer Lib "kernel32.dll" (ByVal hTimer As SafeWaitHandle, ByRef pDueTime As Long, ByVal lPeriod As Integer, ByVal pfnCompletionRoutine As IntPtr, ByVal lpArgToCompletionRoutine As IntPtr, ByVal fResume As Boolean) As Boolean
 
    Public Event Woken As EventHandler
 
    Private bgWorker As New BackgroundWorker()
 
    Public Sub New()
        AddHandler bgWorker.DoWork, AddressOf bgWorker_DoWork
        AddHandler bgWorker.RunWorkerCompleted, AddressOf bgWorker_RunWorkerCompleted
    End Sub
 
    Public Sub SetWakeUpTime(ByVal time As DateTime)
        bgWorker.RunWorkerAsync(time.ToFileTime())
    End Sub
 
    Private Sub bgWorker_RunWorkerCompleted(ByVal sender As Object, ByVal e As RunWorkerCompletedEventArgs)
        RaiseEvent Woken(Me, New EventArgs())
    End Sub
 
    Private Sub bgWorker_DoWork(ByVal sender As Object, ByVal e As DoWorkEventArgs)
        Dim waketime As Long = CLng(e.Argument)
 
        Using handle As SafeWaitHandle = CreateWaitableTimer(IntPtr.Zero, True, Me.[GetType]().Assembly.GetName().Name.ToString() + "Timer")
            If SetWaitableTimer(handle, waketime, 0, IntPtr.Zero, IntPtr.Zero, True) Then
                Using wh As New EventWaitHandle(False, EventResetMode.AutoReset)
                    wh.SafeWaitHandle = handle
                    wh.WaitOne()
                End Using
            Else
                Throw New Win32Exception(Marshal.GetLastWin32Error())
            End If
        End Using
        '' 27/01/2011
        'SetThreadExecutionState(EXECUTION_STATE.ES_SYSTEM_REQUIRED Or EXECUTION_STATE.ES_CONTINUOUS)
        'SetThreadExecutionState(EXECUTION_STATE.ES_DISPLAY_REQUIRED)
 
        '' keyboard event
        'keybd_event(VK_NONAME, 0, KEYEVENTF_SILENT, 0)
 
    End Sub
 
End Class

AnswerUpdate: Code works, but monitor does not come on Pin
PuWii26-May-13 20:12
groupPuWii26-May-13 20:12 
GeneralMy vote of 5 Pin
Deveshdevil8-Apr-13 0:39
memberDeveshdevil8-Apr-13 0:39 
Questionit does't work well like this. Pin
lsf_20085-Nov-12 20:15
memberlsf_20085-Nov-12 20:15 
QuestionCould you code it using vc++? thanks! Pin
lsf_20084-Nov-12 15:41
memberlsf_20084-Nov-12 15:41 
Questionhow to make it wakeup daily instead of specified date? Pin
lordrt19-Aug-12 22:01
memberlordrt19-Aug-12 22:01 
QuestionFuture dates won't work Pin
ChrisPKnight21-Jun-12 6:14
memberChrisPKnight21-Jun-12 6:14 
AnswerRe: Future dates won't work Pin
Daniele Di Sarli21-Jun-12 11:19
memberDaniele Di Sarli21-Jun-12 11:19 
QuestionMy vote of 5 - Now I don't have to turn the server on in the morning Pin
enhzflep16-Jun-12 20:49
memberenhzflep16-Jun-12 20:49 
QuestionDon't wake up Pin
chenwangfen13-Nov-11 15:55
memberchenwangfen13-Nov-11 15:55 
AnswerRe: Don't wake up Pin
Daniele Di Sarli13-Nov-11 19:42
memberDaniele Di Sarli13-Nov-11 19:42 
GeneralRe: Don't wake up Pin
chenwangfen14-Nov-11 15:43
memberchenwangfen14-Nov-11 15:43 
GeneralRe: Don't wake up Pin
Daniele Di Sarli17-Nov-11 23:34
memberDaniele Di Sarli17-Nov-11 23:34 
GeneralMy vote of 5 Pin
Kanasz Robert10-Nov-11 23:41
memberKanasz Robert10-Nov-11 23:41 
GeneralWorks Great Pin
Prasad_MCA15-Aug-11 7:28
memberPrasad_MCA15-Aug-11 7:28 
GeneralThe BackgroundWorker is busy Pin
hnldp2sh10-Mar-11 15:34
memberhnldp2sh10-Mar-11 15:34 
GeneralRe: The BackgroundWorker is busy Pin
Daniele Di Sarli11-Mar-11 4:50
memberDaniele Di Sarli11-Mar-11 4:50 
GeneralRe: The BackgroundWorker is busy Pin
h3mp17-Oct-13 1:25
memberh3mp17-Oct-13 1:25 
GeneralWorks very well with standby and hibernate [modified] Pin
gauravkale22-Feb-11 4:00
membergauravkale22-Feb-11 4:00 
GeneralRe: Works very well with standby and hibernate Pin
Daniele Di Sarli22-Feb-11 8:19
memberDaniele Di Sarli22-Feb-11 8:19 
GeneralScreen stays black Pin
neojudgment18-Jan-11 5:28
memberneojudgment18-Jan-11 5:28 
GeneralRe: Screen stays black Pin
Daniele Di Sarli18-Jan-11 5:38
memberDaniele Di Sarli18-Jan-11 5:38 
GeneralRe: Screen stays black Pin
Daniele Di Sarli18-Jan-11 5:43
memberDaniele Di Sarli18-Jan-11 5:43 
GeneralRe: Screen stays black Pin
neojudgment18-Jan-11 6:03
memberneojudgment18-Jan-11 6:03 
GeneralRe: Screen stays black Pin
Daniele Di Sarli18-Jan-11 6:56
memberDaniele Di Sarli18-Jan-11 6:56 
GeneralRe: Screen stays black Pin
neojudgment27-Jan-11 10:32
memberneojudgment27-Jan-11 10:32 
GeneralRe: Screen stays black Pin
Daniele Di Sarli27-Jan-11 10:53
memberDaniele Di Sarli27-Jan-11 10:53 
GeneralRe: Screen stays black Pin
Si.Jinmin26-Apr-12 20:34
memberSi.Jinmin26-Apr-12 20:34 
QuestionI want to write an event when the machine wakes up. How to go about it Pin
digvijay_nath11-Oct-10 17:16
memberdigvijay_nath11-Oct-10 17:16 
AnswerRe: I want to write an event when the machine wakes up. How to go about it [modified] Pin
Karthik. A11-Oct-10 18:48
memberKarthik. A11-Oct-10 18:48 
GeneralIt works on Windows Vista Ultimate x64 Pin
hswear33-Oct-10 8:40
memberhswear33-Oct-10 8:40 
GeneralRe: It works on Windows Vista Ultimate x64 Pin
Daniele Di Sarli3-Oct-10 10:06
memberDaniele Di Sarli3-Oct-10 10:06 
AnswerRe: It works on Windows Vista Ultimate x64 Pin
digvijay_nath11-Oct-10 17:19
memberdigvijay_nath11-Oct-10 17:19 
GeneralRe: It works on Windows Vista Ultimate x64 Pin
Daniele Di Sarli12-Oct-10 5:23
memberDaniele Di Sarli12-Oct-10 5:23 
GeneralExcellent!!! Pin
Shanthi Diana22-Aug-10 9:32
memberShanthi Diana22-Aug-10 9:32 
GeneralRe: Excellent!!! Pin
Daniele Di Sarli23-Aug-10 3:38
memberDaniele Di Sarli23-Aug-10 3:38 
GeneralIt doesn't work for me Pin
nanfang25-Jul-10 9:45
membernanfang25-Jul-10 9:45 
GeneralRe: It doesn't work for me Pin
Daniele Di Sarli25-Jul-10 10:07
memberDaniele Di Sarli25-Jul-10 10:07 
GeneralRe: It doesn't work for me Pin
nanfang26-Jul-10 17:47
membernanfang26-Jul-10 17:47 
GeneralRe: It doesn't work for me Pin
Daniele Di Sarli26-Jul-10 23:35
memberDaniele Di Sarli26-Jul-10 23:35 
GeneralRe: It doesn't work for me Pin
Oscar Londono3-Oct-10 3:13
memberOscar Londono3-Oct-10 3:13 
GeneralHi Pin
fanan_boy13-May-10 13:12
memberfanan_boy13-May-10 13:12 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    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 | Terms of Use | Mobile
Web01 | 2.8.171019.1 | Last Updated 3 Feb 2014
Article Copyright 2009 by Daniele Di Sarli
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid