Hallo zusammen,
in letzter Zeit häufen sich die "Mein Script funktioniert nicht! Warum?"-Threads hier im Forum (aber andere Foren habens da auch nicht besser^^).
Teilweise stundenlang suchen die Scripter nach dem "Fehler" bevor sie dann entnervt das Script hier einstellen und meist schon nach einigen Minuten eine Lösungsmöglichkeit präsentiert bekommen.....
Diese Lösung wird aber i.d.R. nicht einfach aus dem Hut gezaubert. Sicher gibt es Profis, die mit einem Blick erkennen, woran es hängt, aber in den allermeisten Fällen muss sich auch der Profi durch das Script hindurchwühlen um den Fehler einzugrenzen. Harte, meist überflüssige Arbeit, da die Scripter die Fehler oft selbst einfach finden könnten.
Aber wie findet man nun diese Fehler "professionell"?
Da die meisten wohl Scite als Editor verwenden, wollte ich die Verwendung der "Fehlersuchhilfen" innerhalb des Editors einmal kurz vorstellen. Ich gehe dabei von einer Vollinstallation von Scite aus.
Unter dem Menüpunkt TOOLS finden sie sich, beispielsweise:Debug to MsgBox oder Debug to Console
Ich behaupte jetzt, daß sich mit Hilfe dieser Funktionen 90% der Programmfehler/Probleme innerhalb kürzester Zeit finden und beheben lassen.
Wie das denn? Nunja, in vielen Fällen handelt es sich bei den Problemen um fehlerhaften Umgang mit Variablen.
Bsp: Ein Script erwartet in einer (Endlos-)Schleife einen bestimmten Variablen-Wert, der aber nie erreicht wird. Ergo läuft die Schleife immer weiter, das Script "hängt". Was für ein Glück gibts ein Forum, schnell das Script dort eingestellt und abgewartet! Irgendeiner wird den Fehler schon finden, während man selbst sich die Zeit im Chat vertreibt und fleissig den eigenen Hilfe-Thread "pusht". Allerdings könnte es auch früh morgens sein, niemand ist im Forum aktiv oder man hat selbst den Ehrgeiz den Fehler zu finden!
Jetzt könnte Debug to Console ins Spiel kommen.
Man setzt im Scite den Cursor auf die abzufragende Variable innerhalb der Schleife und drückt ALT+d.
Scite fügt nun eine Zeile in das Script ein. Nach einem F5 um das Script zu starten wird nun jedes Mal, wenn das Script diese Zeile abarbeitet, der Variablenname und der Wert in die Console geschrieben. Alternativ bekommt man mit Debug to MsgBox diese Werte in.....einer Messagebox^^. Nebenbei erfährt man so, ob diese Schleife überhaupt aufgerufen wurde.
Zur Not kann man sich die MsgBox auch mit dem timeout-Parameter einige Sekunden anzeigen lassen, um sie nicht immer von Hand zu bestätigen.
Nach erfolgreicher Fehlersuche lassen sich die eingefügten Zeilen mit Debug Remove Lines wieder entfernen.
Um abzufragen, ob eine Funktion überhaupt aufgerufen wurde, bietet sich in den Scite-Tools die Funktion Trace: Add Func Trace Lines an.
Damit erfährt man durch eine Ausgabe in die Console, ob die Funktionen überhaupt aufgerufen wurden. Mit Hilfe der Informationen aus der Console und/oder den Msgboxen grenzt man nun immer weiter das Problem ein, irgendwann ist der Punkt erreicht, und man hat den Fehler lokalisiert.
Aber wo kommt dieser "Fehler" her? Sehr wahrscheinlich ist ein fehlerhafter (oder falsch interpretierter) Rückgabewert eines AutoIt-Funktionsaufrufs oder eine "falsche" Variable schuld.
Syntaxfehler werden glücklicherweise schon von Scite abgefangen. Falsch geschriebene Variablennamen finden sich, wenn man Opt('MustDeclareVars', 1)in sein Script einfügt.
Im folgenden Beispiel erläutere ich die Vorgehensweise bei der Fehlersuche nach "falschen" Variablen- bzw. Funktionsrückgabewerten.
Beispiel:
Die Funktion MACHWAS() soll aufgerufen werden, wenn der Mauszeiger sich in einem bestimmten Bereich auf dem Bildschirm befindet, d.h. wenn die X-Koordinate der Mausposition größer als 100 ist. Dieser Bereich auf dem Bildschirm (die 100) wird aus einer Datei ausgelesen.
Problem:
Der Mauszeiger befindet sich an der "richtigen" Bildschirm-Position, aber die Funktion MACHWAS() wird nie aufgerufen! Das haben wir mit Trace: Add Func Trace Lines herausgefunden.
Scriptausschnitt:
$wert = filereadline("test.txt") ;Wert aus Datei auslesen (zahl in textdatei = 100)
if mousegetpos() > $wert then machwas() ;wenn X-Koordinate der Mausposition>Wert dann machwas
Dieses "Script" enthält mehrere Stolpersteine. Aber der Reihe nach....
Generell sollte man nach jedem Funktionsaufruf mit dem @error den Fehlercode auswerten!
Aus der Hilfe: Wenn eine Funktion das @error-Flag setzen kann, dann sollte man es immer überprüfen, bevor man einen Rückgabewert benutzt. Wenn @error nämlich einen Fehler anzeigt, dann ist der Rückgabewert generell undefiniert...
Zuerst lassen wir uns mit einer MsgBox den @error anzeigen. Natürlich benutzt man normalerweise die Funktion Debug To MsgBox, aber ich verwende hier der Übersicht halber eine einfache MsgBox. Man kann so alles erforderliche anzeigen lassen.
$wert = filereadline("test.txt") ;Wert aus Datei auslesen (zahl in textdatei = 100)
msgbox(0,"filereadline","@error="&@error) ;@error ist 0 , lt Hilfe kein Fehler
if mousegetpos() > $wert then machwas() ;wenn X-Koordinate der Mausposition>Wert dann machwas
msgbox(0,"mousegetpos()","@error="&@error) ;@error ist 1, lt Hilfe kein Fehler, aber eigentlich sollte MACHWAS() aufgerufen werden!
Beide Male ist kein Fehler innerhalb der Funktionen FileReadLine() bzw MouseGetPos() aufgetreten! Wieso diese Kontrolle nicht ins Script übernehmen?
$wert = filereadline("test.txt") ;Wert aus Datei auslesen (zahl in textdatei = 100)
if @error = -1 then msgbox(0,"Fehler in filereadline()","@error="&@error) ;wenn fehler, dann msgbox
if mousegetpos() > $wert then machwas() ;wenn X-Koordinate der Mausposition>Wert dann machwas
Ich lasse die Zeile "if @error=-1...." im weiteren Verlauf weg, um übersichtlich zu bleiben.
Es ist kein Fehler beim Lesen der Datei aufgetreten. Die Funktion MACHWAS() wurde trotzdem nicht aufgerufen.
Offensichtlich stimmt irgendetwas mit dem IF-Vergleich nicht. Wir schauen mit der Msgbox nach den Variablen.
$wert = filereadline("test.txt") ;Wert aus Datei auslesen (zahl in textdatei = 100)
msgbox(0,"wert=",$wert) ;als $wert wird 100 angezeigt, das stimmt!
if mousegetpos() > $wert then machwas() ;wenn X-Koordinate der Mausposition>Wert dann machwas
Fein, die Datei "test.txt" existiert und wird gelesen, die Messagebox zeigt 100, das klappt ja schon einmal.
Also ist irgendetwas mit dem Rückgabewert von MouseGetPos() faul, also mal in Scite den Cursor auf den Funktionsnamen setzen, F1 drücken und in der HILFE nachlesen....
Aha, in der Hilfe erfahren wir, MouseGetPos ohne Angabe einer Dimension gibt ein ARRAY zurück.
Rückgabewerte: $array[0] = X-Koordinate (horizontal), $array[1] = Y-Koordinate (vertikal)
Dieses Array (und auch sonst eigentlich alle bis zu zweidimensionalen Arrays) könnte man mit _arraydisplay() ausgeben, um nachzuprüfen, ob überhaupt die "richtigen" Werte, hier die Mauskoordinaten, ausgegeben werden.
Damit man _arraydisplay() nutzen kann, muss eine #include-Datei ins Script eingebunden werden. In den Scite-Tools sorgt OrganizeIncludes für das Einbinden der passenden Include-Datei(en)!
$wert = filereadline("test.txt") ;Wert aus Datei auslesen (zahl in textdatei = 100)
msgbox(0,"wert=",$wert) ;wert ausgeben, es wird 100 ausgegeben, stimmt
$array = mousegetpos() ;Koordinaten der Mausposition in array schreiben
_arraydisplay($array) ; zeigt die X-koordinate und Y-Koordinate der Mausposition
Nachdem die Msgbox bestätigt wurde, erscheint ein Fenster mit der Darstellung des Arrays mit den Mauskoordinaten X und Y. Diese Koordinaten erscheinen uns richtig.
Wir wollten die X-Koordinate der Mausposition mit dem Wert in der Datei vergleichen, also gäbe es 2 Möglichkeiten das Script zu ändern: Laut der Hilfe ist die X-Koordinate der Mausposition sowohl in $array[0], als auch in mousegetpos(0) enhalten. Wir entscheiden uns für mousegetpos(0), übergeben diese aber einer weiteren Variablen $Maus_X, denn diese Variable ist wiederum (mit unserer geliebten Msgbox^^) überprüfbar! Um mal schnell ohne Deklaration am Scriptanfang eine temporäre Variable lokal zu verwenden, nutzt man den Befehl LOCAL.
$wert = filereadline("test.txt") ;Wert aus Datei auslesen (zahl in textdatei = 100)
msgbox(0,$wert) ;wert ausgeben, es wird 100 ausgegeben, stimmt
Local $Maus_X = mousegetpos(0) ;X-Koordinaten der Mausposition in Variable schreiben
msgbox(0,"maus_x=",$Maus_X) ;msgbox mit Maus_X =576 erscheint
if $Maus_X > $wert then machwas() ;wenn Mausposition X>Wert dann machwas
Hmmm, das funktioniert immer noch nicht, die Funktion MACHWAS() wird nicht aufgerufen! Die Mauskoordinate 576 ist doch größer als 100, die Messageboxen geben die Variablen doch aus, warum wird denn MACHWAS() trotzdem nicht ausgeführt?!
Hilfe hilft...
In der Hilfe zu FileReadLine() steht folgender Text: "Liest eine Zeile Text aus einer zuvor geöffneten Textdatei."
Zeile Text, Zeile Text...na logo liest die Funktion eine Zeile Text! Die Msgbox zeigt, die Variable $wert hat doch den Wert 100!
Grübel, grübel und studier.....
AAAAAAHHHH, TEXT steht da, TEXT! Jetzt wirds langsam hell, TEXT heisst so viel wie STRING!
Also gibt FileReadLine() einen STRING zurück, in der Variable $wert steht also ein String, in der IF-Abfrage mit der Mausposition wird aber eine Zahl(INTEGER) erwartet. Zwei unterschiedliche Datentypen vergleichen funktioniert nicht, also müssen wir aus dem STRING "100" die Zahl 100 machen:
Die Funktion Number() hilft uns weiter und macht aus dem STRING "100" die Zahl 100.
Ob die Datentypen nun übereinstimmen, kann man sich auch in der MsgBox anzeigen lassen! Die Funktion VarGetType() sollte man daher im Auge behalten und oft nutzen!
$wert=filereadline("test.txt") ;Wert aus Datei auslesen (zahl in textdatei = 100)
msgbox(0,"wert= "&$wert,vargettype(number($wert))) ;wert ausgeben, es wird 100 ausgegeben, stimmt
Local $Maus_X=mousegetpos(0) ;X-Koordinaten der Mausposition in Variable schreiben
msgbox(0,"maus_x= "&$Maus_X, vargettype($Maus_X)) ;msgbox mit Maus_X =576 erscheint
if $Maus_X > number($wert) then machwas() ;wenn Mausposition X>Wert dann machwas
TADAAAA, die Funktion MACHWAS() wird aufgerufen, sobald die X-Koordinate der Maus die 100 übersteigt, also könnte man nun die Messageboxen entfernen (ich kommentiere sie meist nur aus, man braucht sie ggf noch einmal^^), die @error-Abfrage einfügen und das Script kürzen indem man die Hilfsvariable $Maus_X eliminiert.:$wert=filereadline("test.txt") ;Wert aus Datei auslesen (zahl in textdatei = 100)
if @error=-1 then msgbox(0,"Fehler in filereadline()","@error="&@error) ;wenn fehler, dann msgbox
if mousegetpos(0) > number($wert) then machwas() ;wenn Mausposition X>Wert dann machwas
Die von mir geschätzte Zeit für diese "Problemlösung" mit den vorgestellten Methoden ist ca. 5-10 Minuten für einen Anfänger!
Man kann natürlich den Datentyp (VarGetType()) oder die Errorabfrage auch in die Debug-MsgBox einfügen, dazu muß man die Datei "AutoItTools.lua" bearbeiten, ab Zeile 180 gehts dort zur Sache. Wer allerdings nicht weiß was er dort macht, sollte tunlichst die Finger davon lassen.
Vielleicht habt ihr selbst eine Idee oder ein Tool, wie man das "Fehlerfinden" vereinfachen könnte?
Immer her damit, damit die Fehlersuche demnächst etwas flotter vor sich geht!
Also noch einmal zusammengefasst die Vorgehensweise bei der Fehlersuche:
- Fehlerposition mit Debug to MsgBox , Debug to Console und/oder Trace: Add Func Trace Lines eingrenzen.
- nach Funktionsaufrufen den @error nach Möglichkeit abfangen und auswerten
- Variablen und deren Werte mit Debug to MsgBox und Debug to Console abfragen und prüfen
- Datentypen der Variablen mit VarGetType() prüfen
- Arrays mit _arraydisplay() anzeigen
- die Hilfe nutzen und auch die Beispiele dort einmal ansehen bzw ausprobieren!
ciao
Andy