_Timer_SetTimer Skript hängt sich auf

  • Hallo Liebe AutoIt.de-Community

    Ich hab ein Skript, dass mir Software im Hintergrund installiert (einfacher "Run" Befehl). Per GUI soll mir der Fortschritt mitgeteilt werden. Zurzeit mache ich das über eine Sleep Funktion, sodass beispielsweise jede Sekunde die Prozentzahl steigt.

    Zum eigentlichen Problem:

    Ich habe das Problem gehabt, dass mein Skript pausiert wird, wenn ich das Fenster verschiebe während das Fortschrittslabel aktualisiert wird.
    Somit habe ich mich erkundigt und arbeite jetzt mit Edits und Timer. Das Problem ist, dass sich das Skript häufig aufhängt und nicht mehr reagiert.

    Hier mein Skript (Ich hoffe ich hab es ausreichend kommentiert):

    Spoiler anzeigen
    [autoit]

    #include <Array.au3>
    #include <ButtonConstants.au3>
    #include <File.au3>
    #include <GUIConstantsEx.au3>
    #include <EditConstants.au3>
    #include <StaticConstants.au3>
    #include <WindowsConstants.au3>
    #include <Timers.au3>

    [/autoit] [autoit][/autoit] [autoit]

    ;Form
    $frmInstall = GUICreate("Softwareinstallation", 354, 150, -1, -1, $WS_CLIPSIBLINGS)

    [/autoit] [autoit][/autoit] [autoit]

    ;Titel
    $lblTitle = GUICtrlCreateLabel("Software wird installiert...", 27, 16, 175, 20)
    GUICtrlSetFont(-1, 10, 800, 0, "MS Sans Serif")

    [/autoit] [autoit][/autoit] [autoit]

    ;Button "Fenster verstecken"
    $btnHide = GUICtrlCreateButton("Fenster verstecken", 219, 12, 107, 25)

    [/autoit] [autoit][/autoit] [autoit]

    ;TrayItem erstellen
    $showItem = TrayCreateItem("hide window")

    [/autoit] [autoit][/autoit] [autoit]

    Global $lblSW_title[1], $edtSW_progress[1]

    [/autoit] [autoit][/autoit] [autoit]

    ;Labels für Softwaretitel erstellen
    _ArrayAdd($lblSW_title, GUICtrlCreateLabel("Software1", 84, 56, 168, 17, $SS_LEFTNOWORDWRAP))
    _ArrayAdd($lblSW_title, GUICtrlCreateLabel("Software2", 84, 70, 168, 17, $SS_LEFTNOWORDWRAP))

    [/autoit] [autoit][/autoit] [autoit]

    ;Edits für Fortschrittsanzeige erstellen
    _ArrayAdd($edtSW_progress, GUICtrlCreateEdit("warte...", 264, 56, 41, 17, BitOR($ES_CENTER,$ES_READONLY,$ES_WANTRETURN), 0))
    _ArrayAdd($edtSW_progress, GUICtrlCreateEdit("warte...", 264, 70, 41, 17, BitOR($ES_CENTER,$ES_READONLY,$ES_WANTRETURN), 0))

    [/autoit] [autoit][/autoit] [autoit]

    ;GUI und Tray Checks aktivieren
    AdlibRegister("_GUIcheck", 20)
    AdlibRegister("_TrayCheck", 20)

    [/autoit] [autoit][/autoit] [autoit]

    GUISetState(@SW_SHOW)

    [/autoit] [autoit][/autoit] [autoit]

    For $SWcount = 1 To 2 ;Für jede Software bis (hier 2)
    $avgtime = 30 ;# Sleep
    $ZE = $avgtime * 1000 ;# Berechnen
    $sleep = $ZE / 99 ;#

    [/autoit] [autoit][/autoit] [autoit]

    $PID = Run("ein_setup.exe") ;Setup ausführen

    [/autoit] [autoit][/autoit] [autoit]

    $i = 1
    _Timer_SetTimer($frmInstall, $sleep * 2, "_updateProgress") ;für Fortschritts-Update-Funktion
    While $i <= 99 And ProcessExists($PID)
    Sleep($sleep)
    WEnd
    $i = 100

    [/autoit] [autoit][/autoit] [autoit]

    GUICtrlSetData($edtSW_progress[$SWcount], "100%") ;Fortschritt auf 100% setzen

    [/autoit] [autoit][/autoit] [autoit]

    TrayTip("Installation abgeschlossen", GUICtrlRead($lblSW_title[$SWcount]) & " wurde installiert.", 5)
    Next

    [/autoit] [autoit][/autoit] [autoit]

    _Timer_KillAllTimers($frmInstall)
    Sleep(5000)
    Exit

    [/autoit] [autoit][/autoit] [autoit]

    Func _updateProgress($hWnd, $Msg, $iIDTimer, $dwTime)
    #forceref $hWnd, $Msg, $iIDTimer, $dwTime
    If $i <= 99 AND ProcessExists($PID) Then
    GUICtrlSetData($edtSW_progress[$SWcount], $i & "%")
    Sleep($sleep)
    $i += 1
    Return
    EndIf
    _Timer_KillAllTimers($frmInstall)
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _GUIcheck()
    Local $nMsg = GUIGetMsg()
    Switch $nMsg
    Case $btnHide
    TrayItemSetText($showItem, "show")
    GUISetState(@SW_HIDE)
    Case $GUI_EVENT_CLOSE
    Exit
    EndSwitch
    EndFunc ;==>_GUIcheck

    [/autoit] [autoit][/autoit] [autoit]

    Func _TrayCheck()
    Local $nMsg = TrayGetMsg()
    Switch $nMsg
    Case $showItem
    Local $WinState = WinGetState($frmInstall)
    If $WinState = 7 Then
    GUISetState(@SW_HIDE)
    TrayItemSetText($showItem, "show window")
    ElseIf $WinState = 5 Then
    GUISetState(@SW_SHOW)
    TrayItemSetText($showItem, "hide window")
    EndIf
    EndSwitch
    EndFunc ;==>_TrayCheck

    [/autoit]

    Ich hoffe ihr habt für mich eine Lösung :)

    MfG WATERSTORMms

    Einmal editiert, zuletzt von WATERSTORMms (11. Juli 2012 um 08:25)

    • Offizieller Beitrag

    Ist schon klar, das dein Script abkackt.
    Das Sleep innerhalb der Timerfunktion gehört da nicht hin.
    Da die Funktion von deinem Timer aufgerufen wird ist es Sinnfrei, in dieser Funktion zu warten und
    das Resultat ist ein Sciptabsturz.
    2. Absturzgrund ist auch die Tatsache das du den Timer innerhalb der Timerfunktion löschst.
    Warum machst du das nicht nach der While Wend Schleife?

    Im übrigen kannst du das Einfrieren der GUI auch mit einem Timer nicht verhindern, Updates an der GUI werden immer erst
    gemacht wenn dein WindowsMove beendet wird.

    Edit meiner Meinung nach ist auch die Msg Abfrage mittels AdlinRegister eine Potentielle Absturzursache,
    zumal die mit der Selben Wartezeit aufgerufen wird.

    • Offizieller Beitrag

    Hatte gerade nix besseres zu tun. So stürzt das Script nicht mehr ab:

    Spoiler anzeigen
    [autoit]

    #include <Array.au3>
    #include <ButtonConstants.au3>
    #include <File.au3>
    #include <GUIConstantsEx.au3>
    #include <EditConstants.au3>
    #include <StaticConstants.au3>
    #include <WindowsConstants.au3>
    #include <Timers.au3>
    Opt("TrayAutoPause", 0) ;0=no pause, 1=Pause auf 0 setzen, damit nicht das Script pausiert wird, wenn man auf das Tray klickt
    ;Form
    $frmInstall = GUICreate("Softwareinstallation", 354, 150, -1, -1, $WS_CLIPSIBLINGS)

    [/autoit] [autoit][/autoit] [autoit]

    ;Titel
    $lblTitle = GUICtrlCreateLabel("Software wird installiert...", 27, 16, 175, 20)
    GUICtrlSetFont(-1, 10, 800, 0, "MS Sans Serif")

    [/autoit] [autoit][/autoit] [autoit]

    ;Button "Fenster verstecken"
    $btnHide = GUICtrlCreateButton("Fenster verstecken", 219, 12, 107, 25)

    [/autoit] [autoit][/autoit] [autoit]

    ;TrayItem erstellen
    $showItem = TrayCreateItem("hide window")

    [/autoit] [autoit][/autoit] [autoit]

    Global $lblSW_title[1], $edtSW_progress[1]

    [/autoit] [autoit][/autoit] [autoit]

    ;Labels für Softwaretitel erstellen
    _ArrayAdd($lblSW_title, GUICtrlCreateLabel("Software1", 84, 56, 168, 17, $SS_LEFTNOWORDWRAP))
    _ArrayAdd($lblSW_title, GUICtrlCreateLabel("Software2", 84, 70, 168, 17, $SS_LEFTNOWORDWRAP))

    [/autoit] [autoit][/autoit] [autoit]

    ;Edits für Fortschrittsanzeige erstellen
    _ArrayAdd($edtSW_progress, GUICtrlCreateEdit("warte...", 264, 56, 41, 17, BitOR($ES_CENTER, $ES_READONLY, $ES_WANTRETURN), 0))
    _ArrayAdd($edtSW_progress, GUICtrlCreateEdit("warte...", 264, 70, 41, 17, BitOR($ES_CENTER, $ES_READONLY, $ES_WANTRETURN), 0))

    [/autoit] [autoit][/autoit] [autoit]

    ;GUI und Tray Checks aktivieren
    AdlibRegister("_GUIcheck", 50); 20 ms sind zu kurz um die Func aufzurufen, je nach Rechner kann es erheblich länger Dauern die Funktion auszuführen
    ;~ AdlibRegister("_TrayCheck", 20); Ist Quatsch, da im schlimmsten Fall beide Funktionen Gleichzeitig aufgerufen werden und dessen ausführung länger als 20 ms dauert
    ; Wenn schon mit AdlibRegister beide Abfragen in 1 Funktion packen und lange genug warten. 50 ms reichen aus. Die
    ; Funktion wird 20 mal in der Sekunde aufgerufen und so schnell klickt niemand um eine kürzere Zeit notwendig zu machen.
    GUISetState(@SW_SHOW)

    [/autoit] [autoit][/autoit] [autoit]

    For $SWcount = 1 To 2 ;Für jede Software bis (hier 2)
    $avgtime = 30 ;# Sleep
    $ZE = $avgtime * 1000 ;# Berechnen
    $sleep = $ZE / 99

    [/autoit] [autoit][/autoit] [autoit]

    Global $PID = Run("notepad.exe") ;Setup ausführen

    [/autoit] [autoit][/autoit] [autoit]

    $i = 1
    _Timer_SetTimer($frmInstall, $sleep * 2, "_updateProgress") ;für Fortschritts-Update-Funktion
    While $i <= 99 And ProcessExists($PID)
    Sleep(30)
    WEnd

    [/autoit] [autoit][/autoit] [autoit]

    ; $i = 100; vollkommen unnötig, weil du niemals 100 abfragst
    _Timer_KillAllTimers($frmInstall); Hier sollte der Timer gekillt werden
    GUICtrlSetData($edtSW_progress[$SWcount], "100%") ;Fortschritt auf 100% setzen
    TrayTip("Installation abgeschlossen", GUICtrlRead($lblSW_title[$SWcount]) & " wurde installiert.", 5)
    Next

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Sleep(5000)
    Exit

    [/autoit] [autoit][/autoit] [autoit]

    Func _updateProgress($hWnd, $Msg, $iIDTimer, $dwTime)
    #forceref $hWnd, $Msg, $iIDTimer, $dwTime
    ConsoleWrite($i & ":" & $PID & @LF)
    If $i <= 99 And ProcessExists($PID) Then
    GUICtrlSetData($edtSW_progress[$SWcount], $i & "%")
    Sleep($sleep)
    $i += 1
    Return
    EndIf
    EndFunc ;==>_updateProgress

    [/autoit] [autoit][/autoit] [autoit]

    Func _GUIcheck()
    Local $nMsg = GUIGetMsg()
    Switch $nMsg
    Case $btnHide
    TrayItemSetText($showItem, "show")
    GUISetState(@SW_HIDE)
    Case $GUI_EVENT_CLOSE
    Exit
    EndSwitch
    Local $nMsg = TrayGetMsg()
    Switch $nMsg
    Case $showItem
    Local $WinState = WinGetState($frmInstall)
    If $WinState = 7 Then
    GUISetState(@SW_HIDE)
    TrayItemSetText($showItem, "show window")
    ElseIf $WinState = 5 Then
    GUISetState(@SW_SHOW)
    TrayItemSetText($showItem, "hide window")
    EndIf
    EndSwitch
    EndFunc ;==>_GUIcheck

    [/autoit]

    Scheinbar wird durch den Timer trotz WInMove das Control aktualisiert.
    Nebeneffekt: Das Fenster ruckelt ein bisschen wenn man es bewegt. Schau dir mal die Kommentare im Script an.
    Btw. ich hab zum testen mal Notpad benutzt.

  • Ich kann dir wirklich nur danken Raupi. Wie du siehst habe ich nocht nicht viel mit AutoIt und Timern gearbeitet.
    Das mit den Timern und wann ich welche Sleeps einbauen soll, habe ich echt nicht kapiert.

    Danke für deine Hilfe, jetzt versteh ich alles und sorry für das unschöne Skript.

    Edit 2: Der Thread kann übrigens geschlossen werden.

    Einmal editiert, zuletzt von WATERSTORMms (11. Juli 2012 um 08:48)