I want my sleep key back! (or how to hibernate a machine from your app)
One of the first things I do when I get a new desktop machine or install a new build
of Windows is to map the Sleep button on my keyboard to hibernate instead of
suspend. Hibernate makes more sense for these machines because they will never
run on batteries and I want them to be truly off ;). This worked out great because
I have a bunch of first generation Microsft USB keyboards (they are off white with
a row of blue buttons across the top and a normal extended key layout). I got really,
really used to this. I would just hit the sleep key, the machine would
hibernate and I could walk away. No start menu, no mouse, just a simple key press.
Well, my keyboard at home broke and I bought a Microsoft Natural Ergonomic
Keyboard 4000 to replace it. Works great...but there is no Sleep key on the
keyboard! Ergh. So, instead I figured I would map one of the five
customizable keys (which meant I had to run IntelliType as well... <sigh> )
to an application which would hibernate the machine for me. I thought it would be
obvious, but it wasn't.
In the end, the program is quite short, but figuring out
the magic user mode incantations was hard for a kernel curmudgeon like me.
Anyways, here is the app I wrote to get a machine to hibernate and return my ability to
put hibernate machine with a single keypress. All it does is adjust the
process's token to enable SE_SHUTDOWN_NAME and then call SetSystemPowerState().
Simple as it is, I am proud of it ;).
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif // WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdio.h>
BOOL
SetPrivilege(
HANDLE hToken, // access token handle
LPCTSTR lpszPrivilege, // name of privilege to enable/disable
BOOL bEnablePrivilege // to enable or disable privilege
)
{
TOKEN_PRIVILEGES tp;
LUID luid;
if (!LookupPrivilegeValue(NULL, // lookup privilege on local system
lpszPrivilege, // privilege to lookup
&luid)) { // receives LUID of privilege
printf("LookupPrivilegeValue error: %u\n", GetLastError() );
return FALSE;
}
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
if (bEnablePrivilege) {
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
}
else {
tp.Privileges[0].Attributes = 0;
}
//
// Enable the privilege or disable all privileges.
//
if (!AdjustTokenPrivileges(hToken,
FALSE,
&tp,
sizeof(TOKEN_PRIVILEGES),
(PTOKEN_PRIVILEGES) NULL,
(PDWORD) NULL)) {
printf("AdjustTokenPrivileges error: %d / 0x%x\n",
GetLastError(), GetLastError() );
return FALSE;
}
if (GetLastError() == ERROR_NOT_ALL_ASSIGNED) {
printf("The token does not have the specified privilege.\n");
return FALSE;
}
return TRUE;
}
int __cdecl main()
{
HANDLE hToken;
if (!OpenProcessToken(GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
&hToken)) {
printf("open failed %d / 0x%x\n", GetLastError(), GetLastError());
return FALSE;
}
if (SetPrivilege(hToken,
SE_SHUTDOWN_NAME,
TRUE)) {
if (SetSystemPowerState(FALSE, TRUE) == FALSE) {
printf("failed %d / 0x%x\n", GetLastError(), GetLastError());
}
}
else {
printf("set failed %d / 0x%x\n", GetLastError(), GetLastError());
}
return 0;
}
Anonymous
August 28, 2006
try "shutdown.exe /h" next time
I guess you can put this down as 'professional development' though. :-)Anonymous
August 28, 2006
I forgot to mention that I tried that already. The /h option for shutdown.exe was added post XP SP2, which is the OS I really needed this for ;).Anonymous
August 28, 2006
Can this piece od code be the possible solution for this [ http://groups.google.com/group/microsoft.public.win32.programmer.kernel/browse_frm/thread/805ac94f863ef9c6/# ] problem?
aliAnonymous
August 28, 2006
No, it doesn't solve that problem. in the thread, the calleer wants to disable a keyboard sleep button (see my response), here i am replacing a missing button
dAnonymous
August 28, 2006
For this, I use Cygwin's hibernate program; any version of Windows that can hibernate, it'll hibernate.Anonymous
August 29, 2006
well, that requires a toolchain that I don't want to download ;). besides, now i can do fun stuff like set a timer to hiber in 30 minutes and then create a waitable timer to wake the machine up later ;0.
dAnonymous
September 09, 2006
The comment has been removedAnonymous
September 11, 2006
Moso, good question on SetSuspendState(). I didn't know about this function until you asked. It does all of this work for your actually. It will enable the SE_SHUTDOWN_NAME privilege for you before attempting the system power state transition. Definitely makes for a simpler application :).
dAnonymous
November 30, 2006
I am a creature of habit. Once I get into a pattern, especially with keyboard keys (i.e. my sleep keyAnonymous
May 30, 2007
Sorry for bringing this old thread up, but doronh, can you tell me how you create that waitable timer to wake the machine up later? -janiAnonymous
June 14, 2009
PingBack from http://adirondackchairshub.info/story.php?id=2173