Standby/Suspend/Sleep the PC with AHK takes too long Topic is solved

Get help with using AutoHotkey and its commands and hotkeys
User avatar
WAZAAAAA
Posts: 79
Joined: 13 Jan 2015, 19:48

Standby/Suspend/Sleep the PC with AHK takes too long

21 Feb 2019, 21:57

AutoHotkey is consistently slower than many other programs at entering Standby mode (state S3) for me by a few seconds.
Tested on one machine with Win7+Win10 (dual boot) with hiberfil.sys and pagefile.sys OFF and a second Win7 machine with those ON. Admin or not made no difference.
This has been discussed already in the archived forum, but no solution was found. I can't wrap my head around this so I'm looking for help here.

These are the programs and methods I've tested divided by which was faster and which was slower.

FAST:
Spoiler
SLOW:
  • AutoHotkey calling DllCall("PowrProf\SetSuspendState", "int", 0, "int", 1, "int", 1) (from the Shutdown documentation)
  • AutoHotkey calling DllCall("Kernel32\SetSystemPowerState", "int", 1, "int", 1) (SeShutdownPrivilege required)
  • rundll32.exe Powrprof.dll,SetSuspendState (not recommended, Standby only works if Hibernation is disabled)
  • howto_shutdown_windows.exe
Third party programs have some issues like antivirus false-positives, admin privileges, the PsTools have that annoying 1st time boot EULA windows, the PowerShell method is slow as PS alone takes a long time to load, I don't want to click the Start button it's slow I wanna use a hotkey etc. etc... I just want to do it fast with AHK as I put my PC on standby a lot.

Useful resources:
http://blog.clockahead.com/2012/10/windows.html
https://docs.microsoft.com/en-us/windows/desktop/api/powrprof/nf-powrprof-setsuspendstate
https://docs.microsoft.com/en-us/dotnet/api/system.windows.forms.application.setsuspendstate?view=netframework-4.7.2
https://docs.microsoft.com/en-us/windows/desktop/api/winbase/nf-winbase-setsystempowerstate
powercfg -a to check your available power states
powercfg -h off to disable hibernation (S4)



TL;DR putting the PC on standby using AHK is slow for some unknown reason, how do I make it fast like other programs?
YOU'RE NOT ALEXANDER
User avatar
WAZAAAAA
Posts: 79
Joined: 13 Jan 2015, 19:48

Re: Standby/Suspend/Sleep the PC with AHK takes too long

21 Feb 2019, 22:05

maybe this belongs to Bug Reports?
Last edited by WAZAAAAA on 26 Jan 2020, 01:21, edited 1 time in total.
YOU'RE NOT ALEXANDER
User avatar
nnnik
Posts: 4468
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: Standby/Suspend/Sleep the PC with AHK takes too long

27 Feb 2019, 12:51

To be honest I think it should stay in ask for help for now - we will move this to bug reports if somebody has found something relating it to an autohotkey bug.
Recommends AHK Studio
User avatar
WAZAAAAA
Posts: 79
Joined: 13 Jan 2015, 19:48

Re: Standby/Suspend/Sleep the PC with AHK takes too long  Topic is solved

28 Jan 2020, 04:23

Found a solution/workaround by using the undocumented NtInitiatePowerAction (or ZwInitiatePowerAction) in ntdll.

With some debugging I found out that all standby methods will actually call one of those two native API's, so I thought, hey let's just experiment directly with those, and that was a success. The last parameter (asynchronous) is slow when set to false (0) and fast when set to true (1). You can tell that the boolean actually does something by executing the standby DllCall and a MsgBox on the next line. When set to 0 the message box will only appear when waking the PC from sleep. When set to 1 the message box will appear immediately during the fade-to-black transition.
Some details here: https://stackoverflow.com/questions/12022462/installation-of-power-management-api-hooks-on-windows-os-using-c
As for WHY some programs are treated "asynchronously" while others are not, I have no idea.

Here's a working fast standby example with AHK and no external tools (SeShutdownPrivilege needed):

Code: Select all

;enable SeShutdownPrivilege token (example #4 in documentation https://www.autohotkey.com/docs/commands/Process.htm#ListEx)
Process, Exist  ; Sets ErrorLevel to the PID of this running script.
; Get the handle of this script with PROCESS_QUERY_INFORMATION (0x0400):
h := DllCall("OpenProcess", "UInt", 0x0400, "Int", false, "UInt", ErrorLevel, "Ptr")
; Open an adjustable access token with this process (TOKEN_ADJUST_PRIVILEGES = 32):
DllCall("Advapi32.dll\OpenProcessToken", "Ptr", h, "UInt", 32, "PtrP", t)
VarSetCapacity(ti, 16, 0)  ; structure of privileges
NumPut(1, ti, 0, "UInt")  ; one entry in the privileges array...
; Retrieves the locally unique identifier of the privilege:
DllCall("Advapi32.dll\LookupPrivilegeValue", "Ptr", 0, "Str", "SeShutdownPrivilege", "Int64P", luid)
NumPut(luid, ti, 4, "Int64")
NumPut(2, ti, 12, "UInt")  ; Enable this privilege: SE_PRIVILEGE_ENABLED = 2
; Update the privileges of this process with the new access token:
r := DllCall("Advapi32.dll\AdjustTokenPrivileges", "Ptr", t, "Int", false, "Ptr", &ti, "UInt", 0, "Ptr", 0, "Ptr", 0)
DllCall("CloseHandle", "Ptr", t)  ; Close this access token handle to save memory.
DllCall("CloseHandle", "Ptr", h)  ; Close this process handle to save memory.

DllCall("ntdll\ZwInitiatePowerAction", "int", 2, "int", 4, "int", 0x80000000, "int", 1) ;PC standby (S3)
YOU'RE NOT ALEXANDER

Return to “Ask For Help”

Who is online

Users browsing this forum: DooMWhite, Epialis, jeongrak2, karkas, TAC109 and 42 guests