AdlibRegister in v3.3.10.2 geändert/unbrauchbar?

  • Hab mal eben ein älteres Script benutzen wollen welches mit AdlibRegister parallel zum eigentlichen Script Daten aus einer Datei ausliest.
    Leider musste ich feststellen das dies nicht mehr funktioniert.

    Das Problem scheint die Zeit zu sein welche die registrierte Funktion benötigt. Ist diese >= der Zeit die bei AdlibRegister als Parameter angegeben ist, dann wird nur noch die registrierte Funktion ausgeführt für immer.

    Hier das Beispiel ist aus der Hilfe. Default ist 250ms also hab ich ein Sleep(250) in die Funktion gesetzt um das Verhalten zu simulieren.
    Konnte im Changelog nichts dazu finden wurde anscheinend nur ein Bug behoben der mehrere gleichzeitig registrierte Funktionen betrifft.
    Trotzdem bin ich mir sehr sicher, dass dies in früheren Versionen nicht so war. Ist ja auch irgendwie Sinnlos anzugeben nach wie viel ms die Funktion aufgerufen wird. Stattdessen sollte man doch angeben wie viel Zeit zwischen den Aufrufen vergehen sollte. Man kann ja nicht wissen wie lange die Funktion braucht und je nach dem brauch die ja auch unterschiedlich lange. Normal sehr kurz und bei Reaktion auf ne Veränderung dann eventuell einiges länger. Zudem ist das ja auch Hardware abhängig.

    Kann jemand bestätigen dass die Funktion geändert wurde? Gibt es ein Workaround?

    [autoit]


    #include <MsgBoxConstants.au3>

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

    If ProcessExists("SciTE.exe") = 0 Then
    MsgBox($MB_SYSTEMMODAL, "", "You will need SciTE.exe to be running for ConsoleWrite to display.")
    EndIf

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

    Example()

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

    Func Example()
    ; Register the function MyAdLibFunc() to be called every 250ms (default).
    AdlibRegister("MyAdLibFunc")

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

    ; Sleep does not stop AdLib functions from running.
    Sleep(1000)

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

    ; AdLib functions don't run while a blocking function is shown e.g. MsgBox, InputBox, WinWait, WinWaitClose etc.
    MsgBox($MB_SYSTEMMODAL, "", "No console message(s) will be shown whilst the messagebox is displayed.")

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

    ; The AdLib function MyAdLibFunc() will start again.
    Sleep(2000)

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

    ; Unregister the function MyAdLibFunc() from being called every 250ms.
    AdlibUnRegister("MyAdLibFunc")
    EndFunc ;==>Example

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

    Func MyAdLibFunc()
    Sleep(250)
    ; Assign a static variable to hold the number of times the function is called.
    Local Static $iCount = 0
    $iCount += 1

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

    ConsoleWrite("MyAdLibFunc called " & $iCount & " time(s)" & @CRLF)
    EndFunc ;==>MyAdLibFunc

    [/autoit][autoit][/autoit][autoit][/autoit]
  • Mein 3.3.10.2 verhält sich genau so. Auch das hier geht nicht:

    Spoiler anzeigen
    [autoit]


    AdlibRegister("IntervalFunc", 1000)

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

    $i = 0

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

    While True
    ConsoleWrite("MainLoop[" & $i & "]" & @LF)
    $i += 1
    Sleep(500)
    WEnd

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

    Func IntervalFunc()
    AdlibUnRegister("IntervalFunc")

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

    ConsoleWrite("Interval" & @LF)
    Sleep(1000) ; 1000 ms + call zu consolewrite und sleep => die ausführungszeit von IntervalFunc() ist > 1000 ms

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

    AdlibRegister("IntervalFunc", 1000)
    EndFunc

    [/autoit]
  • Prinzipiell würde ich sowieso von AdlibRegister abraten und die Timer Funktionen empfehlen.
    Da das Skript sowieso während der Ausführung der registrierten Funktion gestoppt wird macht das kein Unterschied.
    Nur der Bug von AdlibRegister wird eben so umgangen. :)


  • Genau das war auch mein Gedanke :P und weil dass nicht klappte hab ich den Code Joke noch weiter gezogen. Und siehe da es funktioniert sogar.
    Gut hat der Interpreter keine Gefühle :D.

    [autoit]


    Global $hTimerInit = TimerInit()
    Global $time = 1000
    AdlibRegister("IntervalFunc", $time)

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

    $i = 0

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

    While True
    ConsoleWrite("MainLoop[" & $i & "]" & @LF)
    $i += 1
    Sleep(500)
    If $i = 5 Then
    AdlibUnRegister("IntervalFunc")
    AdlibUnRegister("AdlibDummyFunc")
    EndIf
    WEnd

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

    Func IntervalFunc()
    AdlibRegister("AdlibDummyFunc", $time)
    ConsoleWrite("Interval " & Round(TimerDiff($hTimerInit), 0) & "ms" & @LF)
    ;Sleep($time) ; 1000 ms + call zu consolewrite und sleep => die ausführungszeit von IntervalFunc() ist > 1000 ms
    EndFunc ;==>IntervalFunc

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

    Func AdlibDummyFunc()
    AdlibUnRegister("IntervalFunc")
    ConsoleWrite("AdlibDummyFunc" & @LF)
    AdlibRegister("IntervalFunc", $time)
    EndFunc ;==>AdlibDummyFunc

    [/autoit]

    Auf diese weise entspricht $time ca. der Zeit zwischen den Funktionsaufrufen also die Zeit in der die Main Schleife abgearbeitet wird.
    Interessanterweise wird die DummyFunc nur ausgeführt wenn die IntervalFunc länger dauert als $time. Man kann also $time ein bisschen grösser wählen als die erwartete Lehrlauf Zeit der IntervalFunc. Und dass ohne zu riskieren dass auf langsamerer Hardware die Main Schlaufe nicht mehr ausgeführt wird.

    Prinzipiell würde ich sowieso von AdlibRegister abraten und die Timer Funktionen empfehlen.
    Da das Skript sowieso während der Ausführung der registrierten Funktion gestoppt wird macht das kein Unterschied.
    Nur der Bug von AdlibRegister wird eben so umgangen. :)


    Dauernd wird vom Gebrauch von AdlibRegister abgeraten wieso nur? Das ist als ob man von MsgBox abraten würde, die pausiert nämlich alles und ist deshalb böse :rolleyes: . Eigentlich sollte man es nur mit bedacht einsetzten genau wie die MsgBox. Manchmal ist Pausieren ja genau dass was man will.
    Mit Timer Funktionen meinst du TimerInit/Diff? Damit lässt sich wohl gut Zeit messen aber beim Einsatz von AdlibRegister spielen die Millisekunden meist eher keine Rolle. Ziel ist etwas abzufangen. Ein Fehler eine User Aktion oder Rückmelden von anderen Programmen etc. Die Abfangfunktion einfach in die Main Schleife zu packen ist wohl kaum zu empfehlen. Die kann ja z.b. so ausehen.

    [autoit]

    While 1
    For
    Next

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

    Select
    Case
    Case
    Case
    EndSelect

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

    Do
    Until

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

    For
    For
    Next

    For
    Next

    Do
    Until

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

    For
    Next
    Next
    WEnd

    [/autoit]

    Wo hin jetzt mit der Funktion? Nach jedem While/For/Do/Case einmal aufrufen :wacko:. Was wenn eine andere Funktion Aufgerufen wird die Zeit benötigt und die Main Schlaufe somit pausiert? AdlibRegister :thumbup: .
    Laut der englischen Hilfe mach AdlibRegister übrigens genau dass was da steht d.h. die alte Version hat sich nicht so verhalten wie beschrieben. Die neue schon nur die alte kaputte Funktion war wohl einiges Sinnvoller.
    Hab das selbe alte Script, auf alter AutoIt Version, auf einem viel langsameren Laptop, ausprobiert und da wird die Main Schlaufe nie ganz abgewürgt. Wenn die IntervalFunc länger dauert als der AdlibRegister Zeit Parameter dann wird zwischen den Aufrufen immer mindestens eine Zeile Code aus der Main Schleife ausgeführt. Es kann also nur sehr sehr langsam werden.

    BTW der Workaround wurde heute Nacht um 4 Uhr geschrieben und ist nicht getestet :whistling: . WIe sich das ganez verhaltet wenn man mehrere Funktionene registriert hab ich auch nicht zuendegedacht. Weitere Vorschläge/Workarounds immer her damit :) .

  • Es wird allgemein von Adlib abgetaren, weil man als Programmierer die Kontrolle verliert an welchem Punkt die Funktion ausgeführt wird.
    Eine Registrierte Funktion kann also Daten (z.B. Globale Variablen) beeinflussen, ohne dass man exakt weiß wann diese Beeinflussung stattfindet.

    Mit Timern und Static lassen sich extrem einfach Funktionen bauen die nur alle x ms ausgeführt werden.
    Vorteile:
    - Falls die Funktion ausgeführt wird weiß man genau an welcher Stelle, Komplikationen wie mit Adlib können nicht auftreten.
    - Man kann über die Position von TimerInit() (in der Funktion) bestimmen wie gezählt wird. Ist TimerInit direkt nach TimerDiff wird keine Rücksicht auf die Laufzeit der Funktion genommen, sie wird dann einfach alle x ms aufgerufen. Ist TimerInit ganz am Ende der Funktion wird die Laufzeit einbezogen.
    Nachteile:
    - Man muss die Funktion in die Schleife schreiben, Adlib kann einfach außerhalb der Schleife erledigt werden.
    - Man kann die Funktion nicht anderweitig nutzen. (Man kann also nicht die gleiche Funktion alle 100ms und z.B. alle 500ms laufen lassen, das ließe sich mit etwas Programmieraufwand beheben, aber so komplex braucht man das nicht)
    - Wenn Laufzeiten berücksichtigt werden wird der Programmfluss aufgehalten, kann man aber umgehen, sofern das Problem teilbar ist.

    Spoiler anzeigen
    [autoit]


    Global $iRunTime = TimerInit()

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

    While Sleep(10) And TimerDiff($iRunTime) < 4000
    _MyFunc1(300)
    _MyFunc2(100)
    _MyFunc3(250)
    WEnd

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

    Func _MyFunc1($iTime = 500)
    Local Static $iFuncTimer = TimerInit()
    If TimerDiff($iFuncTimer) < $iTime Then Return
    $iFuncTimer = TimerInit()
    ConsoleWrite('-Func 1 - Time: ' & @SEC & ':' & @MSEC & @CRLF)
    EndFunc

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

    Func _MyFunc2($iTime = 500)
    Local Static $iFuncTimer = TimerInit()
    If TimerDiff($iFuncTimer) < $iTime Then Return
    $iFuncTimer = TimerInit()
    ConsoleWrite('+Func 2 - Time: ' & @SEC & ':' & @MSEC & @CRLF)
    EndFunc

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

    Func _MyFunc3($iTime = 500)
    Local Static $iFuncTimer = TimerInit()
    If TimerDiff($iFuncTimer) < $iTime Then Return

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

    ; Folgende Zeilen umkommentieren, sodass entweder
    ; das Sleep(500) oder die Do Schleife drin sind

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

    ; Berücksichtigung der Laufzeit, sodass das Programm stoppt
    ; Das zu lösende Problem wird als unteilbar angenommen.
    ;~ Sleep(500)

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

    ; Laufzeit ohne Programmstopp, das Problem verbraucht zwar
    ; ca. 500ms, es ist aber teilbar, sodass die anderen Funktionen weiterlaufen.
    Local $t = TimerInit()
    Do
    _MyFunc1(300)
    _MyFunc2(100)
    Sleep(10)
    Until TimerDiff($t) > 500

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

    $iFuncTimer = TimerInit()
    ConsoleWrite('!Func 3 - Time: ' & @SEC & ':' & @MSEC & @CRLF)
    EndFunc

    [/autoit]

    lg
    M