Jump to content

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

Win7 adaptation of intercept hibernation script


  • Please log in to reply
37 replies to this topic
majstang
  • Members
  • 387 posts
  • Last active: Sep 27 2015 01:44 PM
  • Joined: 29 Aug 2008
Hi!

I have spent quite many hours now trying to figure out how to make this script work as good on Win7 as it does on XP as well. Instead of
PBT_APMQUERYSUSPEND and
BROADCAST_QUERY_DENY := 1112363332
the documentation says i should use
SetThreadExecutionState (Enables an application to inform the system that it is in use, thereby preventing the system from entering sleep or turning off the display while the application is running.)
, but I do not find any wParam value for that and I dont really understand how to use it, since it is quite different from the PBT_APMQUERYSUSPEND (Requests permission to suspend the computer). Can somebody clear this up for me?

Here is my WinXP adapted code so far:

#NoTrayIcon
#Persistent
OnMessage(0x0218, "OnPBMsg")
hibernate = 0
Return


OnPBMsg(wParam, lParam, msg, hwnd) {
   global hibernate
   If (wParam = 0 or wParam=4)
   {   ;PBT_APMQUERYSUSPEND
      If (lParam & 1)   ;Check action flag
      {
         if (hibernate = 0)
         {
            SetTimer, InterceptPBMSG, -1
            Return 1112363332
         }
         else
            Return 4
      }
   }
   ;Must return True after message is processed
   Return True
}

InterceptPBMSG:
Secs := 20
SetTimer, CountDown, 1000
MsgBox, 262148, System Hibernation in 20 seconds, Your HTPC is about to be Hibernated.`nAllow it?, %Secs%
SetTimer, CountDown, Off

IfMsgBox, Yes
{
   hibernate = 1
   DllCall("PowrProf\SetSuspendState", "int", 1, "int", 0, "int", 0)
   hibernate = 0
   Return
}
IfMsgBox, Timeout
{
   hibernate = 1
   DllCall("PowrProf\SetSuspendState", "int", 1, "int", 0, "int", 0)
   hibernate = 0
   Return
}
IfMsgBox No
{
   hibernate = 0
   return
}

Return

CountDown:
Secs -= 1
WinSetTitle, System Hibernation in,, System Hibernation in %Secs% seconds
Return


HotKeyIt
  • Moderators
  • 7439 posts
  • Last active: Jun 22 2016 09:14 PM
  • Joined: 18 Jun 2008
Can you try this one, I don't have Win7 so can't try?
As I understand, there is no way to deny hibernation when requested by the user.
All we can do is reset system idle timers.
#NoTrayIcon
#Persistent
ES_AWAYMODE_REQUIRED:=0x00000040
ES_CONTINUOUS:=0x80000000
ES_SYSTEM_REQUIRED:=0x00000001
OnMessage(0x0218, "OnPBMsg")
hibernate = 0
Return


OnPBMsg(wParam, lParam, msg, hwnd) {
   global
   If (wParam = 0 or wParam=4)
   {   ;PBT_APMQUERYSUSPEND
      If (lParam & 1)   ;Check action flag
      {
         if (hibernate = 0)
         {
            SetTimer, InterceptPBMSG, -1
				If A_OSVersion=WIN_VISTA
					DllCall("SetThreadExecutionState","UInt",ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_AWAYMODE_REQUIRED)
            Return 1112363332
         }
         else
            Return 4
      }
   }
   ;Must return True after message is processed
   Return True
}

InterceptPBMSG:
Secs := 20
SetTimer, CountDown, 1000
MsgBox, 262148, System Hibernation in 20 seconds, Your HTPC is about to be Hibernated.`nAllow it?, %Secs%
SetTimer, CountDown, Off
If A_OSVersion=WIN_VISTA
	DllCall("SetThreadExecutionState","UInt",ES_CONTINUOUS)
IfMsgBox, Yes
{
   hibernate = 1
   DllCall("PowrProf\SetSuspendState", "int", 1, "int", 0, "int", 0)
   hibernate = 0 
   Return
}
IfMsgBox, Timeout
{
   hibernate = 1
   DllCall("PowrProf\SetSuspendState", "int", 1, "int", 0, "int", 0)
   hibernate = 0
   Return
}
IfMsgBox No
{
   hibernate = 0
   return
}

Return

CountDown:
Secs -= 1
WinSetTitle, System Hibernation in,, System Hibernation in %Secs% seconds
Return


majstang
  • Members
  • 387 posts
  • Last active: Sep 27 2015 01:44 PM
  • Joined: 29 Aug 2008
Unfortunatly this does not work. Compiling your script and execute it and then sending:
DllCall("PowrProf\SetSuspendState", "int", 1, "int", 0, "int", 0)
hibernation gets executed without any msgbox poping up giving me options what to do next.

majstang
  • Members
  • 387 posts
  • Last active: Sep 27 2015 01:44 PM
  • Joined: 29 Aug 2008
BTW. when debugging for example DVBViewer when sending the hibernation call, the DVBViewer seem to first close down graph and then recieving Powermessage PBT_APMSTANDBY and then the SetThreadExecutionState 0x80000001

SetThreadExecutionState 0x80000003 is the first message it recieves when beginning to resume from hibernation.

Maybe this log could be helpful.

debug.log says:
04.08.10 13:00:35.417 TfrmMain Release Unicast Network Device
04.08.10 13:00:35.417 TfrmMain Destroy Unicast Network Device
04.08.10 13:00:35.417 Sendstr DELPID 18 4102 4358 0 262 1
04.08.10 13:00:35.418 TUCStreamThread Sessionended
04.08.10 13:00:35.418 TWSocketThread Sessionended
04.08.10 13:00:35.419 Powermessage PBT_APMSTANDBY
04.08.10 13:00:37.769 SetThreadExecutionState 0x80000001
04.08.10 13:01:31.512 Time changed
04.08.10 13:01:33.539 SetThreadExecutionState 0x80000003
04.08.10 13:01:34.540 Powermessage PBT_APMRESUMEAUTOMATIC
04.08.10 13:01:34.540 Powermessage PBT_APMRESUMESTANDBY
04.08.10 13:01:34.541 Settuner Start
04.08.10 13:01:34.544 TCMDSocketThread Sessionstarted
04.08.10 13:01:34.544 TUCStreamThread Sessionstarted

HotKeyIt
  • Moderators
  • 7439 posts
  • Last active: Jun 22 2016 09:14 PM
  • Joined: 18 Jun 2008
As far as I understand it will not work when user hibernated.
But we can try that.
ES_AWAYMODE_REQUIRED:=0x00000040
ES_CONTINUOUS:=0x80000000
ES_SYSTEM_REQUIRED:=0x00000001
DllCall("SetThreadExecutionState","UInt",ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_AWAYMODE_REQUIRED)
DllCall("PowrProf\SetSuspendState", "int", 1, "int", 0, "int", 0)
DllCall("SetThreadExecutionState","UInt",ES_CONTINUOUS)


majstang
  • Members
  • 387 posts
  • Last active: Sep 27 2015 01:44 PM
  • Joined: 29 Aug 2008
Im not with you completly now. Do you want me to insert these lines somewhere in the script or test these lines separatley? If inserting them, where to? Tried to insert them like this, but script hibernates PC instantly upon execution.

#NoTrayIcon
#Persistent
ES_AWAYMODE_REQUIRED:=0x00000040
ES_CONTINUOUS:=0x80000000
ES_SYSTEM_REQUIRED:=0x00000001
DllCall("SetThreadExecutionState","UInt",ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_AWAYMODE_REQUIRED)
DllCall("PowrProf\SetSuspendState", "int", 1, "int", 0, "int", 0)
DllCall("SetThreadExecutionState","UInt",ES_CONTINUOUS)
OnMessage(0x0218, "OnPBMsg")
hibernate = 0
Return


OnPBMsg(wParam, lParam, msg, hwnd) {
   global
   If (wParam = 0 or wParam=4)
   {   ;PBT_APMQUERYSUSPEND
      If (lParam & 1)   ;Check action flag
      {
         if (hibernate = 0)
         {
            SetTimer, InterceptPBMSG, -1
            If A_OSVersion=WIN_VISTA
               DllCall("SetThreadExecutionState","UInt",ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_AWAYMODE_REQUIRED)
            Return 1112363332
         }
         else
            Return 4
      }
   }
   ;Must return True after message is processed
   Return True
}

InterceptPBMSG:
Secs := 20
SetTimer, CountDown, 1000
MsgBox, 262148, System Hibernation in 20 seconds, Your HTPC is about to be Hibernated.`nAllow it?, %Secs%
SetTimer, CountDown, Off
If A_OSVersion=WIN_VISTA
   DllCall("SetThreadExecutionState","UInt",ES_CONTINUOUS)
IfMsgBox, Yes
{
   hibernate = 1
   DllCall("PowrProf\SetSuspendState", "int", 1, "int", 0, "int", 0)
   hibernate = 0 
   Return
}
IfMsgBox, Timeout
{
   hibernate = 1
   DllCall("PowrProf\SetSuspendState", "int", 1, "int", 0, "int", 0)
   hibernate = 0
   Return
}
IfMsgBox No
{
   hibernate = 0
   return
}

Return

CountDown:
Secs -= 1
WinSetTitle, System Hibernation in,, System Hibernation in %Secs% seconds
Return


HotKeyIt
  • Moderators
  • 7439 posts
  • Last active: Jun 22 2016 09:14 PM
  • Joined: 18 Jun 2008
Sorry for not being clear.
Try to run it separately and see if it hibernates or not before MsgBox appears
ES_AWAYMODE_REQUIRED:=0x00000040
ES_CONTINUOUS:=0x80000000
ES_SYSTEM_REQUIRED:=0x00000001
DllCall("SetThreadExecutionState","UInt",ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_AWAYMODE_REQUIRED)
DllCall("PowrProf\SetSuspendState", "int", 1, "int", 0, "int", 0)
MsgBox
DllCall("SetThreadExecutionState","UInt",ES_CONTINUOUS)


majstang
  • Members
  • 387 posts
  • Last active: Sep 27 2015 01:44 PM
  • Joined: 29 Aug 2008
Ah, now im with you :)

Well, unfortunatley when testing this code PC hibernates and blackouts before seeing any msgbox. When resuming from hibernation the msgbox is there however.

HotKeyIt
  • Moderators
  • 7439 posts
  • Last active: Jun 22 2016 09:14 PM
  • Joined: 18 Jun 2008

The SetThreadExecutionState function cannot be used to prevent the user from putting the computer to sleep. Applications should respect that the user expects a certain behavior when they close the lid on their laptop or press the power button.



majstang
  • Members
  • 387 posts
  • Last active: Sep 27 2015 01:44 PM
  • Joined: 29 Aug 2008

The SetThreadExecutionState function cannot be used to prevent the user from putting the computer to sleep. Applications should respect that the user expects a certain behavior when they close the lid on their laptop or press the power button.


There must be a workaround, cuz there are applications that have exactly these functions im after, like for example "Don't Sleep" app.
Anyway, big thanks for your help, HotKeyIt!

Anybody else have any ideas on how to crack this?

HotKeyIt
  • Moderators
  • 7439 posts
  • Last active: Jun 22 2016 09:14 PM
  • Joined: 18 Jun 2008
Looks like ShutdownBlockReasonCreate is the way to go.
More information here, look for Using the New Shutdown Reason API
Try this:
Gui,+LastFound
hwnd:=WinExist()
DllCall("ShutdownBlockReasonCreate","Uint",hwnd,"Str",A_ScriptFullPath " is still running")
DllCall("PowrProf\SetSuspendState", "int", 1, "int", 0, "int", 0)
MsgBox
DllCall("ShutdownBlockReasonDestroy","Uint",hwnd)


majstang
  • Members
  • 387 posts
  • Last active: Sep 27 2015 01:44 PM
  • Joined: 29 Aug 2008
I saw that possibility as well when searching around for solutions, but this seem only to apply on shutdown/restart blocking, not standby/hibernate. Tested your code and confirmed:
same scenario as before.

majstang
  • Members
  • 387 posts
  • Last active: Sep 27 2015 01:44 PM
  • Joined: 29 Aug 2008
Last nail in the coffin...the Don't Sleep application doesn't work on prevent/blocking standby or hibernation on Windows 7...it only blocks shutdown/log-off/screensaver/monitor shutdown. On XP everthing works though. Win7 is CRAP and I will never go there again...now back to the only real OS there is! :)

Thanks for all help!

guest3456
  • Guests
  • Last active:
  • Joined: --
can someone please explain why you use a SetTimer, -1 to call a diff subroutine instead of just putting all the code there

  • Guests
  • Last active:
  • Joined: --

can someone please explain...

...yes, if you don't respond to the system restart/shutdown msgs quickly, the system will offer to kill your app. You must quickly tell the system "No!", present any options to the user & then initiate restart/shutdown again, if requested by the user.

I wonder if a driver or anything can make WinVista/Win7 behave like XP? I might not want my computer to refuse to restart/shutdown, but as a programmer, it should be an option. Just one more nail in the Microsoft Coffin, until we all move to ReactOS (if they ever finish it) or something else.