Jump to content

Detecting Windows Shutdown/Logoff


Steph
 Share

Recommended Posts

I've a couple of scripts which sit running permanently in the tray (thanks Holger). When you shutdown or log off I want them to restore certain settings - is there any way to detect that Windows is shutting down or the user is logging off?

I was hoping OnAutoItExit() would help, but the following only seems to work when you choose 'Exit' from the tray.

while 1
    sleep(1000)
WEnd

Func OnAutoItExit()
    MsgBox(64, "Bye", "Going going ...")
EndFunc

I know this has been mentioned before, but I was wondering if there were any events I can trap using the GUI stuff which Windows sends to all running applications...

Thanks

Steph

Link to comment
Share on other sites

Well it's sort of hacky, but you could run your program as a service, with the idea in mind that Windows will shut down other programs before your service (not sure if thats the case, but sounds reasonable). Then you could use ProcessExists to monitor a program that will never be closed unless windows is shutting down (AIM, trillian, whatever for example). If your program sees AIM is not running, you can stop the windows shutdown by typing 'shutdown -a' at the command line. Then do your cleanup, and use Shutdown() to finish...

Link to comment
Share on other sites

Steph,

Found the following on www.myitforum.com (it assumes your running Windows 2000 or later):

You can open the local Group Policy editor.

Or if you need to automate this, then here's a totally unsupported method that may work.

Copy your script to %SystemRoot%\system32\GroupPolicy\Machine\Scripts\Shutdown

Manually edit the %SystemRoot%\system32\GroupPolicy\Machine\Scripts\script.ini file

It has the following format:

[shutdown]

0CmdLine=browse.vbs

0Parameters=

There's also the GPAnywhere tool from www.FullArmor.com which can be used to configure shutdown scripts.

Don't let the talk of Group Policy Objects dissuade from trying this method, your computer doesn't have to be in an Active Directory environment, your simply setting a local group policy on that PC.

ZK

Link to comment
Share on other sites

http://www.autoitscript.com/forum/index.ph...357entry58357

I was suggested to try this but it doesn't work.

If WinExists("Shut Down Windows") Then
      $ScRdrIsWanted = $FALSE;for my needs only in this example
      ExitLoop
    EndIf

J

Edited by jdickens

If I am too verbose, just say so. You don't need to run on and on.

Link to comment
Share on other sites

Well... I believe there is a message "broadcasted" when the system is shutting down. If you can hear it, you can call "abort" shutdown windows api to stop it... how to hear the message?

Lar.

<{POST_SNAPBACK}>

Well, since Larry spoke up, I'm guessing a DLL call would be able to find the broadcast message...since all windows programs SHOULD hear the message (though I'm sure, not all DO) and thereby run though whatever they need to do to close gracefully before windows just outright KILLS the process. :lmao:

Lofting the cyberwinds on teknoleather wings, I am...The Blue Drache

Link to comment
Share on other sites

Well, since Larry spoke up, I'm guessing a DLL call would be able to find the broadcast message...since all windows programs SHOULD hear the message (though I'm sure, not all DO) and thereby run though whatever they need to do to close gracefully before windows just outright KILLS the process.  :lmao:

<{POST_SNAPBACK}>

I've assumed there is some sort of message sent to all programs, but wasn't sure how to 'hear' it. Is there anybody who can suggest what DLL call to use and how (pretty please)?

Steph

Link to comment
Share on other sites

Hi,

i've found this....

'There's a message that you get sent when the system is shutting down, WM_QUERYENDSESSION. As much as I hate using native Win32 functions or message handling in a Windows Forms app, there doesn't appear to be any other way to catch a system shutdown event than to use this. '

Andre

What about Windows without using AutoIt ?It would be the same as driving a car without an steering Wheel!
Link to comment
Share on other sites

Hi,

i've found this....

'There's a message that you get sent when the system is shutting down, WM_QUERYENDSESSION.  As much as I hate using native Win32 functions or message handling in a Windows Forms app, there doesn't appear to be any other way to catch a system shutdown event than to use this. '

Andre

<{POST_SNAPBACK}>

Following up on this. There's no direct path to get the actual message. PeekMessage(), which is the API function you must use requires a structure to work. However, it also supports filtering. If you filter all messages except WM_QUERYENDSESSION, then you can trap the event without worrying about the actual MSG structure.
Link to comment
Share on other sites

I knew this was an impossible task.

Also because you would have to keep checking if the message is sent.

Which means there's very little time to do anything else.

OR, you have a seperate script that listens for the message.

I don't request anything I'm just sharing info.

Link to comment
Share on other sites

Just an idea: "do it the other way " o:)

Instead of using the "windows shutdown" use your own script:

e.g. you will then use this "My Shutdown"

in My Shutdown (or whatever it is),

- you can do you own stuff first (end other scripts or programs, save files , Kill other windows, Close other processes etc... )

- then use "Shutdown" builtin AutoIt function to actually close the system (or restart or ....)

Anyway, there will still be a pending problem - i also have - and which i couldn't find a way thru:

AutoIt "ProcessClose" actally KILL the process, which is not fair if it should do some housekeeping before Closing/Exiting.

No problem if there is a window associated, but sometimes there's no (or i couldn't find it) or you cannot "Exit" from this window but only from "system tray menu" (that's the case for firewall, resident backup sofware etc...).

I found no easy way, yet :lmao: , to activate "system tray menus" from a script.

EDIT> to be more specific, up to now ifound no way to "send" a "Clean Close" message to programs such as ZoneAlarm, NeroBackItUp, Hotsync, K9... <EDIT

Edited by lupusbalo
Link to comment
Share on other sites

Following up on this.  There's no direct path to get the actual message.  PeekMessage(), which is the API function you must use requires a structure to work. 

<{POST_SNAPBACK}>

:lmao: PeekMessage() ??? Is that a new function in the betas? Or just C(++)?

Lofting the cyberwinds on teknoleather wings, I am...The Blue Drache

Link to comment
Share on other sites

Thanks for the suggestions, I'm trying the PeekMessage route, this is what I've got - it doesn't work, just sits there. It's probably something I'm doing - so if someone with more experience with the Windows API and DLL calls can have a look that would be great.

; See http://www.mentalis.org/apilist/PeekMessage.shtml

Const $PM_NOREMOVE = 0
Const $WM_QUERYENDSESSION = 17

$handle=DllOpen("user32.dll")

Dim $dummy[200], $ret[200]

while 1
; (lpMsg As MSG, ByVal hwnd As Long, ByVal wMsgFilterMin As Long, ByVal wMsgFilterMax As Long, ByVal wRemoveMsg As Long) As Long
    $ret=DllCall($handle, "long", "PeekMessage", "ptr", $dummy, "long" , 0, "long" , $WM_QUERYENDSESSION, "long", $WM_QUERYENDSESSION, "long", $PM_NOREMOVE)
    If $ret[0] <> 0 Then
        MsgBox(64, "Bye", "Time to go..", 2)
        Exit
    EndIf
    Sleep(100)
WEnd

Steph

Link to comment
Share on other sites

Larry, it doesn't matter, you can filter out all other messages (Except WM_QUIT). So then it should only fire on any message within the filter range (And WM_QUIT). That means the structure can be totally ignored since only two messages will cause a non-zero return value.

Edit: Steph, just as an experiment, make the first paramter "str" instead of "ptr". Making it "str" will give some memory for the MSG structure to be written to. This _might_ be the reason for it not working. This is just a guess, though.

Edited by Valik
Link to comment
Share on other sites

Not sure if you are looking external to au3 or internal, but there are a couple of free programs to do that:

http://www.google.com/search?hl=en&lr=&saf...down+stopper%22

The one I use is here:

http://www.snapfiles.com/download/dlshutdownstop.html

It can notify and even run a program (autoit3.exe anyone?) when there is a shutdown attempt made.

Who else would I be?
Link to comment
Share on other sites

closest I could come is to get a return by using "int_ptr" for the msg structure instead of "str". But the PeekMessage never finds the WM_QUERYENDSESSION message... I can get other messages (i don't know which because I don't have a msg structure to look at) but when I filter for just the wm_queryendsession msg... no lucky...

Lar.

<{POST_SNAPBACK}>

Larry, it wasn't about getting something to read, it was about avoiding any internal errors where the function demanded a non-null pointer be passed. I know that a couple of the Service-related API functions require a block of memory or they fail. So in those cases, passing a "str" instead of a "ptr" causes them to work. The actual parameter is irrelevant, however, the function demands it be non-null. Since it's still failing, it might just be that WM_QUERYENDSESSION isn't something PeekMessage() will find (By design).
Link to comment
Share on other sites

Not sure if this will help.

This is over my head.

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/sysinfo/base/system_shutdown_functions.asp

indicates many flavors of HOW to shut down the system from C; perhaps one among you can figure out how to detect if this message has been initiated, or how to affect the "priveleges" (MS terminology) of the AutoIt prog.

J :lmao:

If I am too verbose, just say so. You don't need to run on and on.

Link to comment
Share on other sites

Thanks again for everyone's interest, here's my second go ...

; See http://www.mentalis.org/apilist/PeekMessage.shtml

#include <GUIConstants.au3>
#Include <date.au3>

Const $PM_NOREMOVE = 0
Const $PM_REMOVE = 1
Const $WM_QUERYENDSESSION = 17

$handle=DllOpen("user32.dll")
if $handle = -1 then msgbox(64,"Error!","Didn't open DLL!",2) EndIf

Dim $dummy[200], $ret[200]

$window = GUICreate("Main window", 400, 400)
$edit = GUICtrlCreateEdit("", 10, 10, 380, 380, $ES_READONLY + $ES_AUTOVSCROLL)
GUISetState()

$old = -1
while 1
; (lpMsg As MSG, ByVal hwnd As Long, ByVal wMsgFilterMin As Long, ByVal wMsgFilterMax As Long, ByVal wRemoveMsg As Long) As Long
    $ret=DllCall($handle, "long", "PeekMessage", "str", $dummy, "long" , $window, "long" , 0, "long", 1000, "long", $PM_NOREMOVE)
    if @error = 1 Then msgbox(64, "Error!","Error in DllCall",2) EndIf
    if $old<>$ret[0] Then
        GUICtrlSetData($edit, _NowTime() & ": Ret[0] is " & $ret[0] & @crlf, 1)
        $old=$ret[0]
    EndIf
WEnd

... this seems to capture some messages (PeekMessage returns nonzero), but can't tell what and when I filter for WM_QUERYENDSESSION I don't get anything. Larry did you do something like this to get a return of some sort? Reading from jdickens link to ExitWindows does suggest that WM_QUERYENDSESSION is sent to the 'main window' of each application - so I created a window to pass in the call to PeekMessage - is this the main window or is it somewhere else? Another possibility is that I'm not checking the message queue quick enough so I took the 'sleep' out - no joy. The more likely possibility is that I'm straining the limits of my knowledge of Windows and am barking up the wrong tree. Any [further] ideas?

Steph

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...