Click here to Skip to main content
15,891,136 members
Articles / Programming Languages / C
Tip/Trick

How to wake up a PC using waitable timer

Rate me:
Please Sign up or sign in to vote.
4.87/5 (4 votes)
30 Jul 2013CPOL3 min read 32.3K   13   12
How to wake up a PC using waitable timer

Introduction

I used to love listening to the pop-song radio program that aired early in the morning when I was a teenager. However, waking up in the early morning was almost impossible for me, then I couldn’t help wondering how convenient and wonderful it would be if the radio could automatically be turned on and wakes me up. (There was no such thing back then). However, I am guessing that some students nowadays might want the similar function from their PCs, so we are going to cover the method to do so today.

Power state

The power status of the Windows are divided into five main categories. Please refer to the link below for further information.

If we were to categorize the five different power status, we have Operating mode (S0), Sleep mode (S1, S2, S3) and Hibernation (S4), soft off (s5) and Off(G3). The only categories we can wake up the computer via the software is when it's on Sleep mode S1,S2,S3 and S4 mode while hibernation (S4) mode is the most frequently used to turn on the computer automatically as it consumes the lowest amount of power.

Shutdown Privilege

Now we will look at the specific way we can turn the computer back on at a certain time. The most common technique for this would be to turn it off to the hibernation and wake it up at a certain time. Turning off the computer via hibernation mode is extremely simple. All it requires is the code as you see below.

C++
SetSystemPowerState(FALSE, FALSE); 

However, it will not work as well as you expect, as we do not have the authority to turn off the power. Thus, we will need to gain the authority through the code SeShutdownPrivilege. This code allows the authority to turn your computer off via the code “SetSystemPowerState” successfully.

C++
BOOL 
WINAPI  
_EnableShutDownPriv()  
{  
    BOOL ret = FALSE;  
    HANDLE process = GetCurrentProcess();  
    HANDLE token;  
  
    if(!OpenProcessToken(process  
                        , TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY  
                        , &token))  
        return FALSE;  
  
    LUID luid;  
    LookupPrivilegeValue(NULL, "SeShutdownPrivilege", &luid);  
  
    TOKEN_PRIVILEGES priv;  
    priv.PrivilegeCount = 1;  
    priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;  
    priv.Privileges[0].Luid = luid;  
    ret = AdjustTokenPrivileges(token, FALSE, &priv, 0, NULL, NULL);  
    CloseHandle(token);  
  
    return TRUE;  
} 

Waitable Timer

Now I am going to cover the method to wake the computer up. In order to get the computer back on from the hibernation mode, we need what we call ‘waitable timer’, which operates when your PC is in the hibernation mode. Its primary function is as same is the timer, which triggers the event we appointed at the designated time. In other words, the event set in prior is triggered automatically as the code prepared starts its progress. The next code shows us how to use the pre-arranged timer. The only fact you need to be aware in this process is that the unit of time is based on 100 nanoseconds. If you appoint the positive number, it becomes an absolute time, while using appointing negative becomes a relative time. The absolute time is recognized same as FILETIME on Windows. Therefore, as we appoint the negative number as per below, the timer will initiate itself after certain seconds from the moment we set the timer.

C++
HANDLE timer = CreateWaitableTimer(NULL, TRUE, "MyWaitableTimer");  

if(timer == NULL)  
    return FALSE;  
  
__int64 nanoSecs;  
LARGE_INTEGER due;  
  
nanoSecs = -secs * 1000 * 1000 * 10;  
due.LowPart = (DWORD) (nanoSecs & 0xFFFFFFFF);  
due.HighPart = (LONG) (nanoSecs >> 32);  
  
if(!SetWaitableTimer(timer, &due, 0, 0, 0, TRUE))  
    return FALSE; 

The last thing you need to remember is that you need to notify the Windows that certain power is required if you need to turn on the monitor separately once the computer is turned on from the Hibernation mode. All you need is the code as per below, which will trigger the notification and automatically turn on the monitor.

C++
SetThreadExecutionState(ES_DISPLAY_REQUIRED); 

Overall, first you gain the authority, then set the waitable timer and initiate hibernation. When the waitable timer starts its procedure, it notifies the system that we want the power on. This is all done as per the code below.

C++
DWORD 
CALLBACK  
ShutDownProc(LPVOID p)  
{  
    PHANDLE timer = (PHANDLE) p;  
  
    WaitForSingleObject(*timer, INFINITE);  
    CloseHandle(*timer);  
    SetThreadExecutionState(ES_DISPLAY_REQUIRED);   
  
    return 0;  
}  
  
BOOL 
WINAPI  
HibernateAndReboot(int secs)  
{  
    if(!_EnableShutDownPriv())  
        return FALSE;  
  
    HANDLE timer = CreateWaitableTimer(NULL, TRUE, "MyWaitableTimer");  
    if(timer == NULL)  
        return FALSE;  
  
    __int64 nanoSecs;  
    LARGE_INTEGER due;  
  
    nanoSecs = -secs * 1000 * 1000 * 10;  
    due.LowPart = (DWORD) (nanoSecs & 0xFFFFFFFF);  
    due.HighPart = (LONG) (nanoSecs >> 32);  
  
    if(!SetWaitableTimer(timer, &due, 0, 0, 0, TRUE))  
        return FALSE;  
  
    if(GetLastError() == ERROR_NOT_SUPPORTED)  
        return FALSE;  
  
    HANDLE thread = CreateThread(NULL, 0, ShutDownProc, &timer, 0, NULL);  
    if(!thread)  
    {  
        CloseHandle(timer);  
        return FALSE;  
    }  
  
    CloseHandle(thread);  
    SetSystemPowerState(FALSE, FALSE);  
    return TRUE;  
} 

Once your PC is turned on, it will be ready for you to do whatever you would like to do.

License

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


Written By
Chief Technology Officer Wellbia.com Co., Ltd.
Korea (Republic of) Korea (Republic of)
YoungJin is a co-founder of Wellbia.com Co., Ltd., a security company in South Korea, and Visual C++ Microsoft Most Valuable Professional. He has developed anti-cheat program called XIGNCODE since 2007. He wrote several PC security programs like PC Firewall, Anti-Spyware, and Keyboard Security Software. He has contributed a number of articles about Windows programming to Microsoftware, the famous programming magazine of South Korea. He also hosts a blog (http://www.jiniya.net) that includes articles about system programming on Windows.

Comments and Discussions

 
QuestionGood idea Pin
FredWah14-Dec-22 8:43
FredWah14-Dec-22 8:43 
Questionhelp me Pin
mgold500216-Jan-18 21:03
mgold500216-Jan-18 21:03 
QuestionTime for hibernate Pin
Ronny319-Oct-16 21:50
Ronny319-Oct-16 21:50 
AnswerRe: Time for hibernate Pin
Ronny320-Oct-16 0:34
Ronny320-Oct-16 0:34 
QuestionSetSystemPowerState Pin
Roger6530-Jul-13 20:18
Roger6530-Jul-13 20:18 
AnswerRe: SetSystemPowerState Pin
_Nizar31-Jul-13 2:40
_Nizar31-Jul-13 2:40 
GeneralRe: SetSystemPowerState Pin
Ronny35-Jan-17 18:51
Ronny35-Jan-17 18:51 
GeneralRe: SetSystemPowerState Pin
Ronny35-Jan-17 23:00
Ronny35-Jan-17 23:00 
QuestionSetup?? Pin
kccodr30-Jul-13 4:38
professionalkccodr30-Jul-13 4:38 
AnswerRe: Setup?? Pin
_Nizar31-Jul-13 2:35
_Nizar31-Jul-13 2:35 
//File WakingUp.cpp
#include "stdafx.h"
#include "WakingUp.h"

BOOL
WINAPI
_EnableShutDownPriv()
{
BOOL ret = FALSE;
HANDLE process = GetCurrentProcess();
HANDLE token;

if(!OpenProcessToken(process
, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY
, &token))
return FALSE;

LUID luid;
LookupPrivilegeValue(NULL, _T("SeShutdownPrivilege"), &luid);

TOKEN_PRIVILEGES priv;
priv.PrivilegeCount = 1;
priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
priv.Privileges[0].Luid = luid;
ret = AdjustTokenPrivileges(token, FALSE, &priv, 0, NULL, NULL);
CloseHandle(token);

return TRUE;
}


DWORD
CALLBACK
ShutDownProc(LPVOID p)
{
PHANDLE timer = (PHANDLE) p;

WaitForSingleObject(*timer, INFINITE);
CloseHandle(*timer);
SetThreadExecutionState(ES_DISPLAY_REQUIRED);

return 0;
}

BOOL
WINAPI
HibernateAndReboot(int secs)
{
if(!_EnableShutDownPriv())
return FALSE;

HANDLE timer = CreateWaitableTimer(NULL, TRUE, _T("MyWaitableTimer"));
if(timer == NULL)
return FALSE;

__int64 nanoSecs;
LARGE_INTEGER due;

nanoSecs = -secs * 1000 * 1000 * 10;
due.LowPart = (DWORD) (nanoSecs & 0xFFFFFFFF);
due.HighPart = (LONG) (nanoSecs >> 32);

if(!SetWaitableTimer(timer, &due, 0, 0, 0, TRUE))
return FALSE;

if(GetLastError() == ERROR_NOT_SUPPORTED)
return FALSE;

HANDLE thread = CreateThread(NULL, 0, ShutDownProc, &timer, 0, NULL);
if(!thread)
{
CloseHandle(timer);
return FALSE;
}

CloseHandle(thread);
SetSystemPowerState(FALSE, FALSE);
return TRUE;
}
----------------------------------------------------------
//File PCWakingUp.cpp

#include "stdafx.h"
#include "PCwakingUp.h"
#include "WakingUp.h"
#include <windows.h>


//Definitions for the controls
#define BTN1 4000
#define EDIT1 5000

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
static HINSTANCE ghInstance = NULL;

HWND hButton;
HWND hEdit;

/* WinMain(), our entry point */

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR szCmdLine, int iCmdShow) {
static char szAppName[] = "winhello";
HWND hwnd;
MSG msg;
WNDCLASSEX wndclass;

ghInstance = hInstance;

/* Fill in WNDCLASSEX struct members */

wndclass.cbSize = sizeof(wndclass);
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
wndclass.lpszClassName = (LPCWSTR)szAppName;
wndclass.lpszMenuName = NULL;


/* Register a new window class with Windows */

RegisterClassEx(&wndclass);


/* Create a window based on our new class */

hwnd = CreateWindow((LPCWSTR)szAppName,_T("Hello, world!"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
250, 110,
NULL, NULL, hInstance, NULL);


/* Show and update our window */

ShowWindow(hwnd, iCmdShow);
UpdateWindow(hwnd);


/* Retrieve and process messages until we get WM_QUIT */

while ( GetMessage(&msg, NULL, 0, 0) ) {
TranslateMessage(&msg); /* for certain keyboard messages */
DispatchMessage(&msg); /* send message to WndProc */
}


/* Exit with status specified in WM_QUIT message */

return msg.wParam;
}


/* Window procedure */

LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) {
PAINTSTRUCT ps;
HDC hdc;
WORD wmId;

/* Switch according to what type of message we have received */

switch ( iMsg ) {
case WM_CREATE:
hButton = CreateWindowEx(
NULL,
_T("Button"),
_T("Set Timer"),
WS_BORDER | WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
0, 0,
100, 30,
hwnd, (HMENU)BTN1,
ghInstance,
NULL);
hEdit = CreateWindowEx(
NULL,
_T("Edit"),
_T(""),
WS_BORDER | WS_CHILD | WS_VISIBLE,
105, 0,
100, 30,
hwnd, (HMENU)EDIT1,
ghInstance,
NULL);
break;
case WM_PAINT:

/* We receive WM_PAINT every time window is updated */

hdc = BeginPaint(hwnd, &ps);
//BTN = CreateButtonEx( hwnd, IDBTN, 0, 0, 80, 23, "My Push Btton", WS_VISIBLE );
EndPaint(hwnd, &ps);
return 0;

case WM_DESTROY:

/* Window has been destroyed, so exit cleanly */

PostQuitMessage(0);
return 0;

case WM_COMMAND:
wmId = LOWORD(wParam);
switch (wmId)
{
case BTN1:
TCHAR szTemp[128];

GetDlgItemText ( hwnd , EDIT1 , szTemp , 128 );
int secs = atoi((const char *)szTemp);
HibernateAndReboot(secs);
MessageBox(hwnd, _T("Time set"), _T("o,O"), 0);
return 0;
}
}


/* Send any messages we don't handle to default window procedure */

return DefWindowProc(hwnd, iMsg, wParam, lParam);
}
------------------------------------------------------------------------
//File WakingUp.h
#ifndef _WAKINGUP_
#define _WAKINGUP_

static BOOL WINAPI _EnableShutDownPriv();
DWORD CALLBACK ShutDownProc(LPVOID p);
BOOL WINAPI HibernateAndReboot(int secs);

#endif
GeneralRe: Setup?? Pin
kccodr31-Jul-13 6:26
professionalkccodr31-Jul-13 6:26 
GeneralRe: Setup?? Pin
Member 1201525530-Sep-15 0:04
Member 1201525530-Sep-15 0:04 

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.