Click here to Skip to main content
16,011,647 members
Articles / Desktop Programming / Win32

Wake the PC from standby or hibernation

Rate me:
Please Sign up or sign in to vote.
4.94/5 (55 votes)
3 Feb 2014CPOL2 min read 192.3K   4.7K   119   66
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:

C#
[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: 

C#
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:

C#
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:

C#
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: 

C#
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:

C#
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:

C#
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)


Written By
Italy Italy
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionWorks perfectly but why won't it work rewritten as a console app? Pin
johnspeth28-May-24 3:54
johnspeth28-May-24 3:54 
I thank you for giving us a well designed and documented working example. I've studied this and other programs like it (particularly this one). Comparing both source codes show they are derived from the same source but it's not obvious who came first. I've massaged a C code version attempting to replicate the code Mr DiSarli gave us (shown below, built using Vis Studio 2022, pay attention to build configs at top of file). My program DOES NOT WORK when my computer is asleep (works fine when not asleep). DiSarli's code does indeed work regardless of the sleep state and I can't explain why. Can anyone enlighten me? Is it because of the implicit windows message loop running in the DiSarli code? If so, why?
C++
#include <stdio.h>
#include <stdlib.h>

#include <windows.h>

#define	USE_CALLBACK
#define	SET_EVENT_IN_CALLBACK

#define COUNTS_PER_SECOND 10000000

int gNumSeconds = 0;

int gEvidenceCallbackRan = FALSE;

/////////////////////////////////////////////////////////////////////////////
VOID CALLBACK TimerAPCProc(LPVOID lpArg,DWORD dwTimerLowValue,DWORD dwTimerHighValue)
{
	SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_AWAYMODE_REQUIRED);

	MessageBeep(0);

	HANDLE hWoke = *(HANDLE *)(lpArg);

#ifdef SET_EVENT_IN_CALLBACK
	BOOL success = SetEvent(hWoke);
	if(!success)
	{
		printf("SetEvent failed with error %d\n",GetLastError());
	}
#endif

	gEvidenceCallbackRan = TRUE;
}

/////////////////////////////////////////////////////////////////////////////
DWORD CALLBACK MyThread(LPVOID p)
{
	HANDLE hTimer;
	BOOL bSuccess;
	__int64 qwDueTime;
	LARGE_INTEGER liDueTime;

	printf("Start thread\n");

	HANDLE hWoke = *(HANDLE *)(p);

	hTimer = CreateWaitableTimer(	NULL,					// Default security attributes
									FALSE,					// Create auto-reset timer
									"SpethWARE_MyTimer");	// Name of waitable timer
	if(!hTimer)
	{
		printf("CreateWaitableTimer failed with error %d\n",GetLastError());
		return 0;
	}

	// Create an integer that will be used to signal the timer N seconds from now.(negative indicates relative time from "now")
	qwDueTime = -gNumSeconds * COUNTS_PER_SECOND;

	// Copy the relative time into a LARGE_INTEGER.
	liDueTime.LowPart  = (DWORD)(qwDueTime & 0xFFFFFFFF);
	liDueTime.HighPart = (LONG) (qwDueTime >> 32);

	bSuccess = SetWaitableTimer(	hTimer,			// Handle to the timer object
									&liDueTime,		// When timer will become signaled
									0,				// One shot timer (0 means one shot)
#ifdef USE_CALLBACK
									TimerAPCProc,	// Completion routine
#else
									NULL,			// Completion routine (none specified)
#endif
									&hWoke,			// Argument sent to the completion routine
									TRUE);			// Restore a suspended system
	if(!bSuccess)
	{
		printf("SetWaitableTimer failed with error %d\n",GetLastError());
		CloseHandle(hTimer);
		return 0;
	}

	// Wait forever but put the thread in an alertable state so it can return
#ifdef USE_CALLBACK
	// NOTE: Callback will be called - intended
	SleepEx(INFINITE,TRUE);
#else
	// NOTE: Callback will not be called - UNEXPECTED
	DWORD error = WaitForSingleObjectEx(hTimer,INFINITE,TRUE);
	if(error)
	{
		printf("WaitForSingleObjectEx failed with error %d\n",GetLastError());
		CloseHandle(hTimer);
		return 0;
	}
#endif

	CloseHandle(hTimer);

#ifdef SET_EVENT_IN_THREAD
	BOOL success = SetEvent(hWoke);
	if(!success)
	{
		printf("SetEvent failed with error %d\n",GetLastError());
		return 0;
	}
#endif

	printf("Done thread\n");

    return 0;
}

/////////////////////////////////////////////////////////////////////////////
int main(int argc,char *argv[])
{
	if(argc != 2)
	{
		printf("Command line error\n");
		return;
	}

	gNumSeconds = atoi(argv[1]);
	if(gNumSeconds <= 0)
	{
		printf("gNumSeconds range error (%d)\n",gNumSeconds);
		return 0;
	}

	printf("Start main to wait for %d seconds\n",gNumSeconds);

	HANDLE hWoke = CreateEvent(NULL,FALSE,FALSE,NULL);
    if(!hWoke)
    {
		printf("CreateEvent error\n");
        return 0;
    }

    HANDLE hThread = CreateThread(NULL,0,MyThread,&hWoke,0,NULL);
    if(!hThread)
    {
		printf("CreateThread error\n");
        return 0;
    }

	printf("Waiting for hWoke\n");
    DWORD error1 = WaitForSingleObjectEx(hWoke,INFINITE,TRUE);
	if(error1)
	{
		printf("WaitForSingleObjectEx(hWoke) failed with error %d\n",GetLastError());
        return 0;
	}
	printf("Got hWoke\n");

    DWORD error2 = WaitForSingleObjectEx(hThread,INFINITE,TRUE);
	if(error2)
	{
		printf("WaitForSingleObjectEx(hThread) failed with error %d\n",GetLastError());
        return 0;
	}

	CloseHandle(hWoke);

	printf("Callback %s run\n",gEvidenceCallbackRan ? "DID" : "did not");

	printf("Done main\n");

	return 0;
}

JJS

AnswerRe: Works perfectly but why won't it work rewritten as a console app? Pin
johnspeth29-May-24 5:52
johnspeth29-May-24 5:52 
QuestionWorks well as shown, but fails when embedded into a SERVICE Pin
Member 1584479828-Nov-22 2:31
Member 1584479828-Nov-22 2:31 
QuestionIt does not work, in Win 10 Pin
Member 1469394324-Dec-19 7:49
Member 1469394324-Dec-19 7:49 
QuestionDisabled by default for current Windows 10 Pin
Sam Hobbs26-Feb-18 13:00
Sam Hobbs26-Feb-18 13:00 
QuestionHow to turnon monitor at the time of wakeup. Pin
Member 118318764-Apr-16 20:01
Member 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
andrew douse20-Apr-15 21:39 
QuestionCan you provide me with executable please? Pin
Member 20108973-Mar-15 20:10
Member 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
peteSJ3-Feb-14 8:50 
QuestionNice, dude! My vote of 5! Pin
Viktor Signaievskyi1-Feb-14 10:39
Viktor Signaievskyi1-Feb-14 10:39 
BugSystem doesn't wake up Pin
suneth_ac31-Aug-13 22:23
suneth_ac31-Aug-13 22:23 
QuestionCode works, but monitor does not come on Pin
PuWii21-May-13 21:12
PuWii21-May-13 21:12 
AnswerUpdate: Code works, but monitor does not come on Pin
PuWii26-May-13 20:12
PuWii26-May-13 20:12 
GeneralMy vote of 5 Pin
Deveshdevil8-Apr-13 0:39
Deveshdevil8-Apr-13 0:39 
Questionit does't work well like this. Pin
lsf_20085-Nov-12 20:15
lsf_20085-Nov-12 20:15 
QuestionCould you code it using vc++? thanks! Pin
lsf_20084-Nov-12 15:41
lsf_20084-Nov-12 15:41 
Questionhow to make it wakeup daily instead of specified date? Pin
lordrt19-Aug-12 22:01
lordrt19-Aug-12 22:01 
QuestionFuture dates won't work Pin
ChrisPKnight21-Jun-12 6:14
ChrisPKnight21-Jun-12 6:14 
AnswerRe: Future dates won't work Pin
Daniele Di Sarli21-Jun-12 11:19
Daniele 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
enhzflep16-Jun-12 20:49 
QuestionDon't wake up Pin
chenwangfen13-Nov-11 15:55
chenwangfen13-Nov-11 15:55 
AnswerRe: Don't wake up Pin
Daniele Di Sarli13-Nov-11 19:42
Daniele Di Sarli13-Nov-11 19:42 
GeneralRe: Don't wake up Pin
chenwangfen14-Nov-11 15:43
chenwangfen14-Nov-11 15:43 

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.