Jump to content
Sign in to follow this  
ExpertNoob

Close buuton waits for spawned process!

Recommended Posts

ExpertNoob

Hello,

I am making a simple GUI for a command-line executable (my 2nd AutoIt script!).

Once options collected and process started (Run()), clicking the close button of the GUI doesn't have immediate effect! It waits for the spawned process to finish before exiting!

Something I'm missing?

Here is my event handler:

Func Form1Close()
    If $pid<>0 Then ProcessClose($pid)
    Exit
EndFunc
Edited by ExpertNoob

Share this post


Link to post
Share on other sites
GEOSoft

If you used RunWait() to start $pid that is what it will do, Wait.

Otherwise we will have to see enough code to find where you went wrong.


George

Question about decompiling code? Read the decompiling FAQ and don't bother posting the question in the forums.

Be sure to read and follow the forum rules. -AKA the AutoIt Reading and Comprehension Skills test.***

The PCRE (Regular Expression) ToolKit for AutoIT - (Updated Oct 20, 2011 ver:3.0.1.13) - Please update your current version before filing any bug reports. The installer now includes both 32 and 64 bit versions. No change in version number.

Visit my Blog .. currently not active but it will soon be resplendent with news and views. Also please remove any links you may have to my website. it is soon to be closed and replaced with something else.

"Old age and treachery will always overcome youth and skill!"

Share this post


Link to post
Share on other sites
ExpertNoob

If you used RunWait() to start $pid that is what it will do, Wait.

I chose Run() on purpose to be able to offer Pause/Kill buttons..

Here is my master piece:

#include <ButtonConstants.au3>
#include <EditConstants.au3>
#include <GUIConstantsEx.au3>
#include <ProgressConstants.au3>
#include <StaticConstants.au3>
#include <TabConstants.au3>
#include <WindowsConstants.au3>
#include <Constants.au3>

#Include <WinAPI.au3>
#Include <SendMessage.au3>


Opt("GUIOnEventMode", 1)

Global $pathExe, $options, $pid = 0

#Region ### START Koda GUI section ### Form=myGui 0.kxf
$Form1 = GUICreate("myGui 0.1", 562, 268, 455, 309)
GUISetOnEvent($GUI_EVENT_CLOSE, "Form1Close")
GUISetOnEvent($GUI_EVENT_MINIMIZE, "Form1Minimize")
GUISetOnEvent($GUI_EVENT_MAXIMIZE, "Form1Maximize")
GUISetOnEvent($GUI_EVENT_RESTORE, "Form1Restore")

$Label1 = GUICtrlCreateLabel("Exe path:", 8, 8, 74, 17)
;~ GUICtrlSetOnEvent(-1, "Label1Click")

$exePath = GUICtrlCreateInput("C:\MySofts\Dev\Cygwin\bin\sleep.exe", 8, 24, 505, 21)
GUICtrlSetOnEvent(-1, "exePathChange")

$BtBrowse = GUICtrlCreateButton("...", 520, 24, 33, 21, 0)
GUICtrlSetOnEvent(-1, "BtBrowseClick")

$Progress1 = GUICtrlCreateProgress(8, 248, 545, 17)

$Tab1 = GUICtrlCreateTab(8, 59, 545, 137)
GUICtrlSetResizing(-1, $GUI_DOCKWIDTH+$GUI_DOCKHEIGHT)

$TabSheetCommand = GUICtrlCreateTabItem("Command")
$EditCommand = GUICtrlCreateEdit("", 13, 87, 534, 102, BitOR($ES_AUTOVSCROLL, $WS_VSCROLL) )
GUICtrlSetData(-1, "Type options here")
GUICtrlSetOnEvent(-1, "EditCommandChange")
GUICtrlSetTip(-1, "command here")

$TabSheetOutput = GUICtrlCreateTabItem("Output")
GUICtrlSetState(-1,$GUI_SHOW)
$EditOutput = GUICtrlCreateEdit("", 13, 87, 534, 102, BitOR($ES_AUTOVSCROLL,$ES_MULTILINE,$ES_WANTRETURN,$WS_VSCROLL,$ES_READONLY))
GUICtrlSetData(-1, "")
GUICtrlSetOnEvent(-1, "EditOutputChange")

$TabSheetOptions = GUICtrlCreateTabItem("Options")
GUICtrlCreateTabItem("")
GUICtrlSetOnEvent(-1, "Tab1Change")

GUICtrlSetState($TabSheetCommand, $GUI_SHOW); default displayed tab, could be GuiTab.au3//_GUICtrlTab_ClickTab

$BtStart = GUICtrlCreateButton("Start", 294, 201, 243, 33, 0)
GUICtrlSetOnEvent(-1, "BtStartClick")

$BtKill = GUICtrlCreateButton("Kill", 88, 201, 65, 33, 0)
GUICtrlSetState(-1, $GUI_DISABLE)

$BtPause = GUICtrlCreateButton("Pause", 20, 201, 65, 33, 0)
GUICtrlSetState(-1, $GUI_DISABLE)

$Group1 = GUICtrlCreateGroup("", 0, 48, 561, 193)
GUICtrlCreateGroup("", -99, -99, 1, 1)

GUISetState(@SW_SHOW)
#EndRegion ### END Koda GUI section ###

While 1
    Sleep(100)
WEnd

Func BtBrowseClick()

EndFunc

Func BtStartClick()
    $pathExe = GUICtrlRead($exePath)
    $options = GUICtrlRead($EditCommand)
    If Not checkInput() Then return

    $pid = Run ( $pathExe & " " & $options , @SystemDir , @SW_HIDE, $STDERR_MERGED )
    If @error Then
        MsgBox( 48, "Error!", "Failed to start process with:" & @CRLF & @CRLF & $pathExe & @CRLF & @CRLF & _
            _WinAPI_GetLastErrorMessage(), 0, $Form1)
        return
    EndIf
    GUICtrlSetState($TabSheetOutput, $GUI_SHOW)
    
    GUICtrlSetState( $BtPause, $GUI_ENABLE)
    GUICtrlSetState( $BtKill, $GUI_ENABLE)
    
    Local $begin = TimerInit()
    Local $line, $dif, $i = 1
    While 1
        Sleep(50); don't send CPU to 100%!
        $line = StdoutRead($pid)
        If @error Then ExitLoop
        If $line <> "" Then GUICtrlSetData( $EditOutput, $line & @CRLF, " ")
        
        $dif = TimerDiff($begin)
        If $dif >= ($i*100) Then
            GUICtrlSetData( $EditOutput, $dif & @CRLF, " ")
            GUICtrlSetData( $Progress1, 10*$i/20 )
            $i += 1
        EndIf
    Wend

    GUICtrlSetState( $BtPause, $GUI_DISABLE)
    GUICtrlSetState( $BtKill, $GUI_DISABLE)
EndFunc

Func checkInput()
    If $pathExe == 0 Then 
        MsgBox( 48, "Error!", "I cannot read path to executable!")
        return False
    EndIf
    If $pathExe == "" Then 
        MsgBox( 48, "Error!", "No path to executable provided!")
        GUICtrlSetState($exePath, $GUI_FOCUS)
        return False
    EndIf
    
    If $options == 0 Then 
        GUICtrlSetState($TabSheetCommand, $GUI_SHOW); could be GuiTab.au3//_GUICtrlTab_ClickTab
        MsgBox( 48, "Error!", "I cannot read command options!")
        return False
    EndIf
    If $options == "" Then
        GUICtrlSetState($TabSheetCommand, $GUI_SHOW); could be GuiTab.au3//_GUICtrlTab_ClickTab
        MsgBox( 48, "Error!", "No command options! Please type in options")
        GUICtrlSetState($EditCommand, $GUI_FOCUS)
        return False
    EndIf
    
    return True
EndFunc

Func BtKillClick()
    If $pid<>0 Then ProcessClose($pid)
EndFunc

Func BtPauseClick()

EndFunc

Func EditCommandChange()

EndFunc

Func EditOutputChange()

EndFunc

Func exePathChange()

EndFunc

Func Form1Close()
    If $pid<>0 Then ProcessClose($pid)
    Exit
EndFunc

Func Form1Maximize()

EndFunc

Func Form1Minimize()

EndFunc

Func Form1Restore()

EndFunc

Func Tab1Change()

EndFunc

Most event handlers are empty for now, I'm playing with sleep.exe to perform tests..

When I start "sleep.exe 20", clicking the close button (or the kill button) doesn't work. It goes on "sleeping" till the end of the 20 seconds, and then it exits!

Thanks.

Edited by ExpertNoob

Share this post


Link to post
Share on other sites
Authenticity

Problem is that once entered into the loop there is nothing that can stop it in your code. You need Adlib or _Timer_SetTimer or HotKeySet, etc.. to check the button state which means the function needs the get called more frequently than you may guess, maybe like ~100 ms and using _GUICtrlButton_GetState($hButton) to see if the button is clicked. I think the clicked value is 620 and I also may be wrong. ;]

Edited by Authenticity

Share this post


Link to post
Share on other sites
ExpertNoob

@Authenticity

Thanks.

Since I registered an event handler with the close button:

GUISetOnEvent($GUI_EVENT_CLOSE, "Form1Close")

Isn't Form1Close() called as soon as I click the close button? Even if BtStartClick() is busy with its spawned process..

That's why I avoided RunWait(), so that event handlers keep receiving messages while spawned process is running..

If I understand you, it's pointless to define event handlers: each time I enter an event handler, I have to keep checking for state of all other controls inside the current one! That can't be :D

Edited by ExpertNoob

Share this post


Link to post
Share on other sites
Authenticity

OK, I see I'm writing enough crappy details to myself ;]. So I'll just say this:

There is a message queue for each thread that is managed as a linked-list (First In First Out). If the thread is busy handling an event then it's in blocking mode and can't receive and handle any other events until it's done processing the current event. Now timer event, hot-key event, and because of it, Adlib events are not PostMessage events like most of the control notification. They interrupt the thread current execution and control is passes to the interrupt routine until it's done processing it's code and control is return to the thread. Crappy explanation right?

You can test it your self. Make 2 programs. First program sends a user message to the second process (SendMessage!), now the second process start to loop for 10 seconds. Try to interact with the the first program that sent the message and see what happen.

So because you're adopting GuiOnEventMode you'll need to take care not to block the entire message queue handling a single event for 20 seconds. If you need example about AdlibEnable with _GuiCtrlButton_GetState() I'd like to help.

Hope I didn't write too much crap at once.

Edit:

Opt('GuiOnEventMode', 1)

Dim $hGUI = GUICreate('Test', 100, 115)
Dim $Button1 = GUICtrlCreateButton('Test1', 20, 40, 60, 23)
Dim $Button2 = GUICtrlCreateButton('Test2', 20, 80, 60, 23)

GUICtrlSetOnEvent($Button1, 'TestFunc1')
GUICtrlSetOnEvent($Button2, 'TestFunc2')
GUISetOnEvent(-3, '_EXIT')

GUISetState()

While 1
    Sleep(20)
WEnd

Func _EXIT()
    GUIDelete()
    Exit
EndFunc

Func TestFunc1()
    ToolTip('Try to close the window' & @LF & 'or better click "Test2"', @DesktopWidth-140, 0)
    Sleep(10000)
EndFunc

Func TestFunc2()
    ConsoleWrite('-Got a message :-)' & @LF)
EndFunc
Edited by Authenticity

Share this post


Link to post
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
Sign in to follow this  

×