Jump to content

Console app 'OnAutoItExit' callback function


rover
 Share

Recommended Posts

OnAutoItExit() functionality for console apps

this example will stop Ctrl-C and Ctrl-Break from closing a console app

then run a cleanup function before exiting.

can also call system 'EndProgram' EndNow/Cancel dialog for console Close, Log Off or Shutdown

OS: Win 2000 and up

tested on XP only

some MSDN reference links:

CTRL+C and CTRL+BREAK Signals

http://msdn.microsoft.com/en-us/library/ms682541.aspx

SetConsoleCtrlHandler Function

http://msdn.microsoft.com/en-us/library/ms686016(VS.85).aspx

Registering a Control Handler Function

http://msdn.microsoft.com/en-us/library/ms685049(VS.85).aspx

#AutoIt3Wrapper_Change2CUI=y
If Not @Compiled Then Exit

Global Const $CTRL_BREAK_EVENT = 1
Global Const $CTRL_C_EVENT = 0
Global Const $CTRL_CLOSE_EVENT = 2
Global Const $CTRL_LOGOFF_EVENT = 5
Global Const $CTRL_SHUTDOWN_EVENT = 6

Local $fCloseFlag = False
Local $fCancelExit = False
Local $line = ""

;Register control handler callback
Local $hStub_CtrlHandler = DllCallbackRegister("_CtrlHandler", "long", "dword")
Local $aRet = DllCall("Kernel32.dll", "int", "SetConsoleCtrlHandler", "ptr", DllCallbackGetPtr($hStub_CtrlHandler), "dword", 1)

Local $file = FileOpen("con", 4)
ConsoleWrite(@CRLF & "'Exit'/Ctrl-C/Ctrl-Break/Titlebar/Menu - Runs cleanup then exits: " & @CRLF)

While 1
    $line = BinaryToString(FileRead($file, 128))
    If StringInStr($line, "exit", -1) <> 0 Then _Cleanup();type exit to close
    If $fCloseFlag Then _Cleanup()
    If $fCancelExit Then
    ;restart callback and console read functions
        $fCancelExit = False
        $file = FileOpen("con", 4)
        DllCall("Kernel32.dll", "int", "SetConsoleCtrlHandler", "ptr", DllCallbackGetPtr($hStub_CtrlHandler), "dword", 1)
    EndIf
WEnd


;MSDN
;The system generates CTRL_CLOSE_EVENT, CTRL_LOGOFF_EVENT, and CTRL_SHUTDOWN_EVENT signals when the user closes the console,
;logs off, or shuts down the system so that the process has an opportunity to clean up before termination.
;Console functions, or any C run-time functions that call console functions,
;may not work reliably during processing of any of the three signals mentioned previously.
;The reason is that some or all of the internal console cleanup routines may have been called before executing the process signal handler.

;NOTE: you cannot call cleanup functions from the handler (won't run properly) for CTRL_C_EVENT and CTRL_BREAK_EVENT,
;set a flag and call cleanup functions from main loop.
;cleanup functions must be called from handler for CTRL_CLOSE_EVENT as app will exit after returning false from CTRL_CLOSE_EVENT message


Func _CtrlHandler($dwCtrlType)
    Switch $dwCtrlType
        Case $CTRL_C_EVENT
            ConsoleWrite('Ctrl-C event: ' & $dwCtrlType & @CRLF);debugging only
            $fCloseFlag = True;cleanup function must be called from loop
            Return True; Return True prevents exit: block exit or set flag for cleanup before exit
        Case $CTRL_BREAK_EVENT
            ConsoleWrite('Ctrl-Break event: ' & $dwCtrlType & @CRLF)
            $fCloseFlag = True;cleanup function must be called from loop
            Return True; Return True prevents exit: block exit or set flag for cleanup before exit
        Case $CTRL_CLOSE_EVENT
        ;closing command window by titlebar button or menu: optionally run cleanup before exit or return to app if user cancels exit
        ;ConsoleWrite('Ctrl-Close event: ' & $dwCtrlType & @crlf);debugging only
            _Cleanup(True);cleanup function must be called from here
            $fCancelExit = True; if user selects cancel from system 'EndProgram' popup dialog box set flag to re-start required functions from main loop
        ;Return False; No XP popup cancel exit dialog
        ;(if slow functions called before this line then endprogram dialog box does not appear)
            Return True; XP popup cancel exit dialog (can continue app if user clicks dialog cancel button)


        ;CTRL+CLOSE Signal: http://msdn.microsoft.com/en-us/library/ms682535(VS.85).aspx
        ;Vista and Windows 2008 behaviour difference  (comment by David Lowndes)
        ;Where the documentation currently says:
        ;"Return TRUE. In this case, no other handler functions are called,
        ;and a pop-up dialog box asks the user whether to terminate the process."
        ;This is correct for Windows XP, but by default Windows Vista and 2008 server do not show a dialog box,
        ;the process terminates with no further user interaction.
        Case $CTRL_LOGOFF_EVENT; User Log Off and Shutdown events
        ;inconsistent: sometimes exits before returning from cleanup function
        ;ConsoleWrite('Ctrl-Logoff event: ' & $dwCtrlType & @crlf);debugging only
            _Cleanup(True)
        ;for best responsiveness, do not call anything before next line if you want system endprogram dialog to postpone log off or shutdown
        ;(if slow functions called before this line then endprogram dialog box does not appear)
            Return True; XP popup cancel exit dialog (can continue app if user clicks dialog cancel button)
        ;Return False; No XP popup cancel exit dialog

;~      Case $CTRL_SHUTDOWN_EVENT; Not called for shutdown or restart, use log off
;~      ;ConsoleWrite('Ctrl-Shutdown event: ' & $dwCtrlType & @crlf);debugging only
;~          _Cleanup(True)
;~          Return False
    EndSwitch
    Return False
EndFunc  ;==>_CtrlHandler

Func _Cleanup($iExitMode = False)
    FileClose($file)
    DllCall("Kernel32.dll", "int", "SetConsoleCtrlHandler", "ptr", 0, "dword", 0);remove control handler
    If $iExitMode Then Return; DllCallbackFree crashes app if called for CTRL_CLOSE_EVENT message
    DllCallbackFree($hStub_CtrlHandler)
    Beep(1000, 5)
    Exit
EndFunc  ;==>_Cleanup

I see fascists...

Link to comment
Share on other sites

works really well but i get a -1 critical error when starting the app with cmd.exe and clicking on menu or the [x] if i directly start the exe it works fine.

best regards,

JR.

$a=StringSplit("547275737420796F757220546563686E6F6C75737421","")
For $b=1 To UBound($a)+(-1*-1*-1)step(2^4/8);&$b+=1*2/40*µ&Asc(4)
Assign("c",Eval("c")&Chr(Dec($a[$b]&$a[$b+1])));''Chr("a")&"HI"
Next ;time_U&r34d,ths,U-may=get$the&c.l.u.e;b3st-regards,JRSmile;
MsgBox(0x000000,"",Eval("c"));PiEs:d0nt+*b3.s4d.4ft3r.1st-try:-)
Link to comment
Share on other sites

works really well but i get a -1 critical error when starting the app with cmd.exe and clicking on menu or the [x] if i directly start the exe it works fine.

best regards,

JR.

Thanks Zedna, JRSmile

Hi JRSmile

what AutoIt version?, probably not relevant

what OS?

screenshot of dialog?

background processes running?

I assume that's the AutoIt error dialog and not the long windows exception dialog (running DllCallBackFree from the handler caused that one)

maybe PM me a compiled script

the Ctrl-C/Ctrl-Break blocking is the best performing of this API

the MSDN remarks as I've included mention possible problems with the other messages.

I've run this example as console app standalone or from cmd.exe from Run dialog or typed into existing cmd console

Ctrl-C/Ctrl-Break/'Exit'/Menu and button close without a crash on 3 XP systems, one system does not have the popup

endprogram dialog enabled (Don't remember where that option is set or if it is an option, maybe something is turned off or

broken on that XP system)

closing a cmd.exe window by X button or menu when the script is running will occasionally not return from the cleanup function

before exiting. (this is only happening on one of the three XP systems) the CTRL_LOGOFF_EVENT message also has this problem.

reliability of CTRL_CLOSE_EVENT and CTRL_LOGOFF_EVENT exit cleanup needs some work...

I see fascists...

Link to comment
Share on other sites

@Teslafreak, your welcome

@JRSmile

I can get the AutoIt Error Line -1 undeclared variable dialog, but only by placing a blocking MsgBox in Cleanup() (sleep doesn't even do it)

the problem is the handler function is called in a new thread on each event. (creates a new thread for each event then destroys it on return)

I did not pay too much attention to this and its consequences at first as my only programming experience is with the single thread dimension of AutoIt.

so that limits the OnAutoItExit usefulness unless some inter thread code can allow functions called in Cleanup()

for messages CTRL_CLOSE_EVENT and CTRL_LOGOFF_EVENT in the handler thread to work reliably with vars declared in the main thread.

(CTRL_SHUTDOWN_EVENT message only sent if console app is a service, which requires RegisterServiceCtrlHandlerEx API)

a least the Ctrl-C/Ctrl-Break blocking works o.k.

I have to leave this for knowledgeable Win32 programmers to comment on.

I see fascists...

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...