Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

SetSuspendState takes too many time


  • Please log in to reply
8 replies to this topic
bogser
  • Members
  • 9 posts
  • Last active: Apr 05 2012 07:37 AM
  • Joined: 09 Jan 2011
Windows 7 64-bit Ultimate
Autohotkey_L 1.1.07.03 (Unicode 64-bit)
Hybrid sleep is off (http://maximumpcguid...p-in-windows-7/)
Hibernation is off (powercfg -h off)
Pagefile is off, RAM 4GB

When I select Sleep item from windows start menu, computer switches to standby in 2 seconds.

If SetSuspendState is invoked from autohotkey it takes 8-10 seconds
#Esc::
    DllCall("PowrProf\SetSuspendState", "Char", 0, "Char", 1, "Char", 0)
    return
I've written simple C++ app that invokes SetSuspendState. It takes 2 seconds as Sleep item in start menu does.
#include <Windows.h>
#include <PowrProf.h>

#pragma comment(lib, "PowrProf.lib")

int main()
{
    SetSuspendState(FALSE, TRUE, FALSE);
    return 0;
}
So, seems problem is inside autohotkey.

PS
There is a mistake in example section of http://www.autohotke...ds/Shutdown.htm. Statement DllCall("PowrProf\SetSuspendState", "int", 0, "int", 0, "int", 0) is wrong. SetSuspendState declaration:
typedef unsigned char BYTE;
typedef BYTE BOOLEAN;
BOOLEAN WINAPI SetSuspendState(BOOLEAN Hibernate, BOOLEAN ForceCritical, BOOLEAN DisableWakeEvent);
So, proper variant is: DllCall("PowrProf\SetSuspendState", "Char", 0, "Char", 0, "Char", 0)

  • Guests
  • Last active:
  • Joined: --
Umm, no...

A 32-bit integer (the most common integer type), whose range is -2147483648 (-0x80000000) to 2147483647 (0x7FFFFFFF). An Int is sometimes called a "Long".

An Int should also be used for each BOOL argument expected by a function (a BOOL value should be either 1 or 0).

An unsigned Int (UInt) is also used quite frequently, such as for DWORD.



bogser
  • Members
  • 9 posts
  • Last active: Apr 05 2012 07:37 AM
  • Joined: 09 Jan 2011
BOOL is not BOOLEAN
typedef int BOOL;
typedef unsigned char BYTE;
typedef BYTE BOOLEAN;
BOOLEAN is 1 byte, BOOL is 4 bytes

YMP
  • Members
  • 424 posts
  • Last active: Apr 05 2012 01:18 AM
  • Joined: 23 Dec 2006
I don't think it would make much difference here. In x86, each integer parameter occupies 4 bytes on the stack, even if it's only a 1-byte value. The function knows it needs the first byte only. In x64, the first four integer parameters are passed in registers, a whole 8-byte register for each, so again it doesn't seem to make any difference if you pass an int instead of a char.

Btw, strictly speaking, since BOOLEAN is unsigned, it should be "uchar", not "char".

Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006
All input integer values the size of a pointer or smaller are equivalent. Scripts natively use signed 64-bit integers. On x64, all parameters are 64-bit. On x86-32, all parameters which are not (u)int64 are truncated to 32 bits. Even without relying on the current behaviour of DllCall, passing an "int" value to a function expecting "char" (but not vice versa) is guaranteed to work since the function will use only the low 8 bits of the value.

Furthermore, the "u" prefix has no effect since the same binary value will be passed either way. For example, given two 64-bit integers 255 and -1, the low 8 bits of both are the same. If the function interprets it as char, it will be -1; if uchar, it will be 255.

However, this does not apply to the return value or output values of parameters with the * or P suffix.


Anyway, the OP's script works just fine for me.

Windows 7 64-bit
AutoHotkey_L 1.1.07.03 (Unicode 64-bit and Unicode 32-bit)

I've written simple C++ app that invokes SetSuspendState.

Your C++ app is statically linked to PowrProf.dll. On the other hand, DllCall loads it dynamically, calls the function, then unloads PowrProf.dll. You can load it in advance to prevent this from occurring, though I don't know if it will make any difference since the function obviously works.
DllCall("LoadLibrary", "str", "PowrProf")


bogser
  • Members
  • 9 posts
  • Last active: Apr 05 2012 07:37 AM
  • Joined: 09 Jan 2011
Lexikos, YMP
Thanks for detailed response.

Anyway, the OP's script works just fine for me.

Have you disabled hybrid sleep? How much time is taken by your computer to switch to standby by pressing Sleep in start menu and by autohotkey?

Have checked the script on another computer (my notebook with windows 7 home premium 64-bit, hybrid sleep is off, pagefile.sys and hyberfile.sys are on):
- Sleep in start menu and the c++ app takes 4 seconds to switch to standby.
- Autohotkey takes 9 seconds for that.

Also checked old autohotkey 1.0.48.05, its behavior is the same as 1.1.07.03 :(

Your C++ app is statically linked to PowrProf.dll.

DllCall("LoadLibrary", "str", "PowrProf") has not changed anything. Seems problem is that SetSuspendState takes too many time if it's invoked from autohotkey, not long loading of PowrProf.dll. I see this because my monitor is turned off as soon as I press hotkey.

  • Guests
  • Last active:
  • Joined: --
Just out of curiosity, does using the Run command from AHK with
rundll32 PowrProf.dll SetSuspendState 0 1 0
work any faster?

bogser
  • Members
  • 9 posts
  • Last active: Apr 05 2012 07:37 AM
  • Joined: 09 Jan 2011
"rundll32 PowrProf.dll,SetSuspendState 0 1 0" usually invokes "SetSuspendState(SomethingNotZero, 0, SomethingNotZero)" in fact. It does not matter what arguments your specify in rundll32 command.
It's so because rundll32 assumes that declaration of specified function is "void CALLBACK EntryPoint(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow)", see http://support.microsoft.com/kb/164787 for details. But SetSuspendState declaration is "BOOLEAN WINAPI SetSuspendState(BOOLEAN Hibernate, BOOLEAN ForceCritical, BOOLEAN DisableWakeEvent)"
So, "rundll32 PowrProf.dll,SetSuspendState 0 1 0" hybernates a computer in fact (or switches to standby in case if hiberfile.sys is off as I know).

I checked running of my standby c++ app from autohotkey through Run command, it works as fast as when I run it directly.

bogser
  • Members
  • 9 posts
  • Last active: Apr 05 2012 07:37 AM
  • Joined: 09 Jan 2011
Hmm, interesting. I notice that "rundll32.exe PowrProf.dll,SetSuspendState" (equivalent to SetSuspendState(1,0,1)) switches computer to standby if hyberfile.sys is off and takes as much time as when SetSuspendState(0,1,0) is invoked from autohotkey.

I wrote simple TestRun.dll that exports function for rundll32.exe with proper declaration and invokes SetSuspendState:
#include <Windows.h>
#include <PowrProf.h>

#pragma comment(lib, "PowrProf.lib")

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
    return TRUE;
}

void CALLBACK SetSuspendStateProxy(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow)
{
    SetSuspendState(0, 1, 0);
}
And command "rundll32.exe TestRun.dll,SetSuspendStateProxy" works as long as SetSuspendState in autohotkey. So, there is something in rundll32.exe also that cause SetSuspendState to work longer than usual.
Hope this helps.