Funktionen


Inhaltsverzeichnis

Einführung und einfache Beispiele

Eine Funktion ist vergleichbar mit einer Subroutine (Gosub), nur dass sie zusätzlich Parameter (inputs) von ihrem Caller (frei übersetzt in etwa "Aufrufer", also die Instanz, die die Funktion aufruft) entgegennimmt. Zusätzlich kann eine Funktion an ihren Caller einen Wert zurückgeben. Werfen Sie einen Blick auf die folgende, einfache Funktion, die als Eingabe (input) zwei Zahlen akzeptiert und deren Summe zurückliefert:

Add(x, y)
{
return x + y ; "Return" erwartet einen Ausdruck.
}

Das obige Konstrukt bezeichnet man als Funktionsdefinition, da es eine Funktion namens "Add" (Groß-/Kleinschreibung irrelevant) erstellt und festlegt, dass jeder, der die Funktion aufruft, genau zwei Parameter (x und y) bereitstellen muss. Um die Funktion aufzurufen, weisen Sie ihren Wert einfach mit Hilfe des := Operator einer Variablen zu. Siehe dazu folgendes Beispiel:

Var := Add(2, 3) ; Die Zahl 5 wird in der Variablen "Var" gespeichert.

Eine Funktion kann auch aufgerufen werden, ohne ihren Wert einer Variablen zuzuweisen:

Add(2, 3)

In dem Fall wird der Rückgabewert der Funktion verworfen. Wenn die Funktion also nichts anderes bewirkt, als einen Wert zurückzugeben, hätte ihr Aufruf keinen Sinn.

Da ein Funktionsaufruf ein Ausdruck ist, sollten Variablennamen in der Parameterliste nicht in Prozentzeichen eingeschlossen werden. Im Gegensatz dazu sollten explizite (literale) Zeichenketten in Anführungszeichen gesetzt werden. Zum Beispiel:

if InStr(MeineVar, "fox")
MsgBox Die Variable MeineVar enthält das Wort fox.

Abgesehen von OutputVar- und InputVar-Parametern wie z.B. denen des StringLen Befehls, können in den Parametern jedes Befehls Funktionen aufgerufen werden. Parameter, die keine Ausdrücke (expressions) unterstützen, müssen wie in dem folgenden Beispiel den "% " Präfix verwenden:

MsgBox % "Die Anwort ist: " . Add(3, 2)

Der "%" Präfix ist auch in solchen Parametern erlaubt, die normalerweise Ausdrücke unterstützen. In dem Fall wird er einfach ignoriert.

Parameter

Wenn eine Funktion definiert wird, werden ihre Parameter in Klammern neben ihrem Namen aufgelistet (Zwischen Funktionsname und der geöffneten Klammer darf kein Leerzeichen vorhanden sein). Wenn eine Funktion keine Parameter akzeptieren soll, lassen Sie die Klammer einfach leer. Zum Beispiel: GetCurrentTimestamp().

ByRef Parameter: Aus Sicht der Funktion sind Parameter das gleiche wie lokale Variablen es sei denn, sie werden als ByRef Parameter wie in folgendem Beispiel definiert:

Swap(ByRef Links, ByRef Rechts)
{
Temp := Links
Links := Rechts
Rechts := Temp
}

In obigem Beispiel sorgt die Verwendung von ByRef dafür, dass jeder Parameter ein Alias für die Variable wird, die ihr vom Caller übergeben wird. Mit anderen Worten, die Parameter und die Variablen des Callers beziehen sich beide auf den selben Inhalt im Arbeitsspeicher. Das erlaubt der Swapfunktion die Variablen des Callers (Aufrufers) zu verändern, indem es den Inhalt von Links nach Rechts verschiebt und umgekehrt.

Im Gegensatz dazu wären, für den Fall dass ByRef im oberen Beispiel nicht zur Anwendung käme, Links und Rechts Kopien der Variablen des Callers und die Swapfunktion hätte keine externen Auswirkungen (extern im Sinn von außerhalb der Funktion).

Da Return nur einen einzigen Wert zum Caller der Funktion zurückliefert, kann ByRef dazu genutzt werden, zusätzliche Ergebnisse zurückzuliefern. Das erreicht man dadurch, das der Caller eine (meist leere) Variable übergibt, in der die Funktion dann einen Wert ablegen kann.

Für den Fall, dass man lange Zeichenketten an eine Funktion übergeben muss, steigert ByRef die Effizienz und spart Arbeitspeicher, da keine Kopie der Zeichenkette erstellt werden muss. Genauso verhält es sich, wenn man ByRef dazu verwendet, eine lange Zeichenkette an den Caller (Aufrufer) zurückzuliefern. Diese Vorgehensweise ist effizienter als etwa Return LangeZeichenkette.

Bekannte Einschränkung:

Optionale Parameter

Wenn man eine Funktion definiert, kann man einen oder mehrere Parameter als optional auszeichnen. Das erreicht man, indem man ein Gleichheitszeichen gefolgt von einem Standardwert anschließt. Im folgenden Beispiel ist der Z Parameter optional:

Add(X, Y, Z = 0)
{
return X + Y + Z
}

Wenn der Caller drei Parameter an die Funktion übergibt, wird der Standardwert für Z ignoriert. Wenn der Caller allerdings nur zwei übergibt, erhält Z automatisch den Wert 0.

Optionale Parameter zwischen Nicht-optionalen Parametern sind innerhalb der Parameterliste nicht erlaubt. Mit anderen Worten, alle Parameter die rechts neben dem ersten optionalen Parameter liegen, müssen ebenfalls als optional deklariert werden.

Ab Version v1.0.46.13+, unterstützen ByRef Parameter ebenfalls Standardwerte; zum Beispiel: Func(ByRef p1 = ""). Wenn bei Aufruf der Funktion solch ein Parameter weggelassen wird, erstellt die Funktion eine lokale Variable die den Standardwert enthält. Mit anderen Worten, die Funktion verhält sich so, als wäre das Schlüsselwort "ByRef" nicht mit angegeben worden.

Als Standardwert eines Parameters sind folgende Werte erlaubt: true, false, ein expliziter (literaler) Integer- oder Gleitkommawert oder eine literale Zeichenkette wie "fox" oder "" (In Versionen vor 1.0.46.13+ ist nur "" erlaubt).

Lokale und globale Variablen

Lokale Variablen

Alle Variablen die innerhalb einer Funktion referenziert oder erstellt werden sind standardmäßig lokal (ausgenommen durch AHK vorgegeben Variablen wie Clipboard, ErrorLevel und A_TimeIdle). Der Inhalt der lokalen Variablen ist nur für die Codezeilen sichtbar/verfügbar, die innerhalb der Funktion liegen. Daraus folgt, dass eine lokale Variable den gleichen Namen wie eine globale Variable haben kann. In dem Fall haben beide Variablen einen unterschiedlichen Inhalt. Alle lokalen Variablen sind beim jedem Aufruf einer Funktion zu Beginn leer.

Globale Variablen

Um innerhalb einer Funktion eine bereits existierende Variable zu referenzieren (oder eine neue zu erzeugen) müssen Sie die Variable vor dem ersten Gebrauch als global deklarieren. Beispielsweise:

LogToFile(TextToLog)
{
global LogFileName ; Diese globalen Variable wurde zuvor ein Wert außerhalb dieser Funktion zugewiesen.
FileAppend, %TextToLog%`n, %LogFileName%
}

Wenn eine Funktion eine Vielzahl von globalen Variablen referenzieren oder erstellen soll, kann sie so definiert werden, dass die Funktion davon ausgeht, dass alle Variablen global sind (ausgenommen die funktionseigenen Parameter). Dazu schreibt man entweder einfach in die erste Zeile der Funktion das Wort "global" oder man deklariert zu Beginn eine lokale Variable. Siehe dazu folgendes Beispiel:

SetDefaults()
{
global ; Dieses Wort kann weggelassen werden, wenn in der ersten Zeile so etwas wie "local MeineVar" steht.
Var := 33 ; Weise 33 einer globalen Variable zu; falls nötig wird die Variable dabei angelegt.
local x, y:=0, z ; Lokale Variablen müssen hier deklariert werden, ansonsten würde davon ausgegangen, dass alle global sind.
; ...und so weiter.
}

Dieser "Ich gehe davon aus, dass alle Variablen global sind" Modus (assume-global mode) kann von Funktionen auch dazu genutzt werden, um ein globales Array anzulegen. Beispielhaft dafür ist z.B. ein Loop (Schleife) der jedem Array%A_Index% einen Wert zuweist.

Statische Variablen

Eine Variable kann auch als static deklariert werden. Das bewirkt, dass ihr Wert zwischen den Funktionsaufrufen erhalten bleibt. Beispiel:

LogToFile(TextToLog)
{
static LineCount = 0
LineCount += 1 ; Pflegen einer Kontrollvariablen (Ihr Wert bleibt zwischen den Funktionsaufrufen erhalten.
global LogFileName
FileAppend, %LineCount%: %TextToLog%`n, %LogFileName%
}

Statische Variablen sind ohne Ausnahme lokal. In Versionen vor 1.0.46 waren alle statischen Variablen zu Beginn leer. Um also festzustellen, ob eine Variable zum ersten Mal benutzt wurde, musste man nur überprüfen ob sie leer war. In allen späteren Versionen (v1.0.46+) können statische Variablen mit etwas anderem als "" initialisiert werden, indem man := oder = gefolgt von einem der folgenden Werten anschließt: true, false, einen expliziten (literalen) Integer- oder Gleitkommawert oder eine explizite Zeichenkette wie "fox". Beispiel: static X:=0, Y:="fox". Jede statische Variable wird nur eine einziges Mal initialisiert (bevor das Skript ausgeführt wird).

Mehr über lokale und globale Variablen

Mehrere Variablen können in einer Zeile deklariert werden, indem man sie durch ein Komma abtrennt. Beispiel:

global LogFileName, MaxRetries := 5
static TotalAttempts = 0, PrevResult

Ab Version 1.0.46 kann eine globale oder lokale Variable bereits in der gleichen Zeile initialisiert werden, in der sie deklariert wird. Man schließt einfach := oder = (Der = Operator verhält sich in Deklarationen genau wie der := Operator) gefolgt von einem Ausdruck an. Wenn sich in einer Zeile mehr als eine Deklaration befindet, wird jede Deklaration die auch eine Initialisierung beinhaltet, aus Performancegründen als Einzelzeile ausgeführt (Im Gegensatz zu normalen Komma-getrennten Statements). Im Gegensatz zu statischen Initialisierungen wird sie bei lokalen und globalen Variablen jedesmal ausgeführt, wenn die Funktion aufgerufen wird. Es sei denn, der Kontrollfluß erreicht diese Stelle in der Funktion nicht. Mit anderen Worten: eine Zeile wie local x = 0 hat den gleichen Effekt als würde man folgendes schreiben: local x gefolgt von x = 0.

Da die Wörter local, global und static abgearbeitet werden, sobald das Skript startet, kann eine Variable nicht in Abhängigkeit einer bestimmten Bedingung wie einem IF statement deklariert werden. Anders gesagt heißt das, dass eine Deklaration innerhalb eines If oder Else Blocks ohne Rücksicht auf die gestellte Bedingung für alle Zeilen zwischen der Deklaration und der schließenden Klammer der Funktion immer wirksam ist. Beachten Sie bitte auch, dass es im Moment noch nicht möglich ist, eine dynamische Variable wie global Array%i% zu erstellen.

Innerhalb einer Funktion löst sich jede Referenzierung einer dynamischen Variablen wie Array%i% immer zu einer lokalen Variable auf, sofern keine Variable mit diesem Namen existiert. Sollte das der Fall sein, wird die globale Variable genutzt. Wenn weder eine lokale noch eine globale Variable existieren, und es erforderlich wird, die Variable zu erstellen, so wird die Variable lokal erstellt. Es sei denn, die Funktion ist so definiert, dass alle Variablen global erstellt werden (assume-global mode). Als Konsequenz aus dem oben geschriebenen kann eine Funktion nur dann manuell (im Sinn von Array%i% := A_Index) ein globales Array erstellen, wenn die Funktion so definiert wurde, das Variablen standardmäßig als global erstellt werden (assume-global mode).

Bei Befehlen, die ein Array erstellen (wie z.B. StringSplit), wird das Array als lokale Variable erstellt, wenn der assume-global mode nicht angewendet wird, oder das erste Element des Arrays als lokale Variable deklariert wurde (das ist auch der Fall, wenn einer der Funktionsparameter übergeben wird -- sogar falls dies ein ByRef Parameter ist -- da Parameter vergleichbar mit lokalen Variablen sind). Wenn im Umkehrschluß das erste Element des Arrays als global deklariert wurde, wird ein globales Array erstellt. Das erste Element von StringSplit ist ArrayName0. Bei anderen Array-erstellenden Befehlen wie WinGet List, ist das erste Element ArrayName (also ohne die Nummer).

Häufiges Missverständnis: Jede nicht-dynamische Referenzierung einer Variablen erstellt diese in dem Moment, in dem das Skript startet. Wenn beispielsweise MsgBox %Array1% außerhalb einer Funktion genutzt wird, wird Array1 als globale Variable erstellt in dem Moment in dem das Skript startet. Anders herum erstellt MsgBox %Array1%, wenn es innerhalb einer Funktion aufgerufen wird, Array1 als eine lokale Variable der Funktion in dem Moment wo das Skript gestartet wird. (Es sei denn, der assume-global mode wird genutzt).

Short-circuit Boolean Evaluation

Wenn innerhalb eines Ausdrucks AND, OR, bzw. der ternäre (dreifache) Operator verwendet werden, schließen sich diese kurz, um die Performance zu steigern (unabhängig davon, ob Funktionsaufrufe vorhanden sind). Das sogenannte Short-circuiting funktioniert so, dass es bestimmte Teile, die das finale Ergebnis möglicherweise nicht beeinflußen, einfach nicht ausgewertet werden. Folgendes Beispiel illustriert das Konzept:

if (FarbName <> "" AND not FindeFarbe(FarbName))
MsgBox %FarbName% konnte nicht gefunden werden.

Im oberen Beispiel wird die FindeFarbe() Funktion niemals aufgerufen, wenn die Variable FarbeName leer ist, da die linke Seite des AND false (unwahr) wäre. Die rechte Seite des AND könnte das Endergebnis in dem Fall niemals true (wahr) werden lassen.

Wegen dieses Verhaltens ist es wichtig zu begreifen, dass eventuelle Änderungen die eine Funktion vornimmt (wie das Ändern des Werts einer globalen Variable), unter Umständen niemals stattfindet, wenn die Funktion auf der rechten Seite von AND oder OR aufgerufen wird.

Außerdem wird die sogenannte 'short-circuit-evaluation' innerhalb verschachtelter ANDs und ORs nur Stück für Stück ausgewertet. Im folgenden Ausdruck wird zum Beispiel nur der ganz linke Vergleich überprüft, wenn FarbName leer ist. Und zwar aus dem Grund, da die linke Seite bereits ausreichend ist, um das Endergebnis mit Sicherheit vorauszusagen:

if (FarbName = "" OR FindeFarbe(FarbName, Region1) OR FindeFarbe(FarbName, Region2))
break ; Nichts zu durchsuchen, oder es wurde etwas gefunden.

Wie aus dem obenstehenden Beispiel ersichtlich wird, sollten rechenintensive (zeitraubende) Funktionen generell auf der rechten Seite eines AND oder OR aufgerufen werden, um die Performance des Skripts zu erhöhen. Diese Technik kann auch dazu genutzt werden, einen Funktionsaufruf zu verhindern, wenn einer ihrer übergebenen Parameter ungültig wäre (z.B. eine leere Zeichenkette).

Der dreifach bedingte (ternäre) Operator (?:) ab Version v.1.0.46+ ist auch einer dieser 'short-circuits', da der nicht zutreffende Teil nicht ausgewertet wird.

Subroutinen innerhalb einer Funktion nutzen

Auch wenn eine Funktion keine anderen Funktionsdefinitionen enthalten darf, sind Subroutinen selbstverständlich erlaubt. Wie andere Subroutinen werden auch diese per Gosub aufgerufen. Mit Return kehrt man zur Funktion zurück (In dem Fall gehört das Return zum GoSub Befehl und nicht der Funktion).

Bekannte Einschränkungen: Im Moment muss der Name jeder Subroutine (label) innerhalb des gesamten Skripts eindeutig sein. Das Programm weist Sie auf die Existenz von doppelten Labels hin.

Wenn eine Funktion den Gosub Befehl nutzt, um eine öffentlichen Subroutine (eine die außerhalb der Funktionsdefinition liegt) aufzurufen, sind alle Variablen die außerhalb der Funktion liegen global. Auf die funktionseigenen lokalen Variablen kann währenddessen nicht zugegriffen werden, bis die Subroutine in die Funktion zurückgekehrt ist (return).

Auch wenn von der Verwendung von Goto generell abgeraten wird, kann es innerhalb einer Funktion dazu genutzt werden, um an eine andere Position innerhalb der gleichen Funktion zu springen. Das kann hilfreich sein, um komplexe Funktionen, mit mehreren Rückgabestellen/-werten zu vereinfachen, wenn an jedem dieser Rückgabepunkte vor der eigentlichen Werterückgabe bestimmte Aufräumaktionen durchgeführt werden sollen.

Auch wenn ein Goto Befehl, dessen Ziel außerhalb der Funktion liegt, ignoriert wird, kann eine Funktion per Gosub zu einer externen/öffentlichen Subroutine aus der Funktion springen, und dann von dort einen dementsprechenden Goto Befehl ausführen.

Eine Funktion kann extern aufrufbare Subroutinen wie Timer, GUI g-labels, und Menüeinträge enthalten. Das macht man normalerweise, um diese Routinen in eine separate Datei auszulagern und diese dann per #Include einzubinden. Auf diese Weise beeinflußen sie nicht den Auto-Execute Bereich eines Skripts. Trotzdem gelten folgende Beschränkungen:

Return, Exit und allgemeine Bemerkungen

Wenn bei Ausführung der Funktion die schließende Klammer der Funktion erreicht wird, ohne vorher auf ein Return zu stoßen, wird die Funktion beendet, und es wird ein leeres Ergebnis (leere Zeichenkette) an den Caller zurückgegeben. Das gleiche gilt für den Fall, wenn dem Return Befehl kein Parameter übergeben wird oder auf den Einsatz von Return verzichtet wird.

Wenn eine Funktion den Exit Befehl nutzt, um den aktuellen Thread, zu beenden, erhält der Caller niemals einen Rückgabewert. Die Zeile Var := Add(2, 3) würde beispielsweise Var nicht verändern, wenn die Funktion Add() mittels Exit beendet wird. Das gleiche passiert, wenn die Funktion einen Laufzeitfehler verursacht, wie das Ausführen einer nicht existenten/nicht auffindbaren Datei (In diesem speziellen Fall aber nur, wenn auf den Einsatz von UseErrorLevel verzichtet wird).

Eine Funktion kann den Wert der ErrorLevel Variable ändern, um einen einfach zu merkenden zusätzlichen Wert zurückzugeben.

Um eine Funktion mit einem oder mehreren leeren Parametern (leere Zeichenkette) aufzurufen, benutzen sie einfach ein Paar Anführungszeichen, wie in folgendem Beispiel:
FindeFarbe(FarbName, "")

Da der Aufruf einer Funktion keinen neuen Thread startet, werden eventuelle Änderungen an Einstellungen wie SendMode und SetTitleMatchMode durch die Funktion auch für dessen Caller wirksam.

Der Caller einer Funktion darf eine nicht existente Variable oder Array an die Funktion übergeben. Das ist zum Beispiel nützlich, wenn die Funktion davon ausgeht, dass der entsprechende Parameter ein ByRef Parameter ist. Der Aufruf GetNextLine(LeeresArray%i%) würde beispielsweise die Variable LeeresArray%i% automatisch als lokale oder globale Variable erstellen (In dem Fall kommt es darauf an, ob der Aufruf innerhalb einer Funktion erfolgte, oder der assume-global mode aktiv ist).

Wenn ListVars innerhalb einer Funktion aufgerufen wird, zeigt der Befehl eine Liste der lokalen Variablen der Funktion an, inklusive deren Werte bzw. Inhalt. Das kann beim Debuggen eines Skripts helfen.

Stil und Namensvergabepraxis

Sie werden feststellen, dass komplexe Funktionen viel besser les- und pflegbar sind, wenn deren spezielle Variablen mit einem eindeutigen Präfix (Kürzel) gekennzeichnet sind. Wenn Sie zum Beispiel jedem Parameter in der Funktionsparameterliste ein "p" oder "p_" voranstellen, wird auf einen Blick deutlich, welchem Zweck diese Variablen dienen. Besonders, wenn die Funktion eine Unzahl von lokalen Variablen besitzt, die überblickt werden müssen. Der Präfix "r" bzw. "r_" könnte auf diese Weise zum Beispiel für ByRef Parameter verwendet werden. Für statische Variablen bietet sich "s" oder "s_" an.

Ab Version v1.0.41 kann auch der One True Brace (OTB) Blockstil verwendet werden, um Funktionen zu definieren. Beispiel:

Add(x, y) {
return x + y
}

#Include nutzen, um Funktionen in mehreren Skripten einzusetzen

Die #Include Direktive kann dazu genutzt werden, um Funktionen aus einer externen Datei nachzuladen (sogar am Anfang eines Skripts).

Erklärung: Wenn das Skript bei der Ausführung auf eine Funktionsdefinition trifft, überspringt sie diese und fährt mit der Ausführung in der Zeile nach der schließenden Klammer der Funktion fort. Daraus folgt, dass das Skript während der Ausführung niemals versehentlich in eine davor definierte Funktion springt. Auch eine oder mehrere Funktionen, die zu Beginn des Skripts notiert sind, beeinflußen den Auto-execute Bereich eines Skripts nicht.

Funktionsbibliotheken: Standardbibliothek und Benutzerbibliothek [v1.0.47+]

Ein Skript kann auch ohne den #Include Befehl eine Funktion aus einer externen Datei aufrufen. Damit das funktioniert, muss eine Datei gleichen Namens wie der der Funktion in einem der folgenden Bibliotheksverzeichnisse vorhanden sein:

%A_MyDocuments%\AutoHotkey\Lib\ ; Benutzerbibliothek. Dieses Verzeichnis ist optional. Es kann sogar ganz fehlen.
Pfad-zur-aktuell-laufenden-Autohotkey.exe\Lib\ ; Standardbibliothek.

Wenn ein Skript zum Beispiel eine nicht existierende Funktion MyFunc() aufruft, sucht das Programm nach einer Datei namens MyFunc.ahk in der Benutzerbibliothek. Wenn sie dort nicht gefunden wird, versucht es das gleiche in der Standardbibliothek. Wenn die Funktion dann immer noch nicht auffindbar ist und der Funktionsname einen Unterstrich enthält (z.B. MyPrefix_MyFunc), sucht das Programm in beiden Bibliotheken nach einer Datei namens MyPrefix.ahk und lädt diese, falls sie existiert (dies erlaubt MyPrefix.ahk die Zuständigkeit für die Funktion MyPrefix_MyFunc, wie auch für andere, verwandte/zugehörige Funktionen, deren Name mit MyPrefix_ beginnt).

Obwohl eine Bibliotheksdatei in der Regel nur eine einzige Funktion mit dem gleichen Namen wie der der Datei enthält, kann sie auch andere private Funktionen und Subroutinen enthalten, die nur von dieser Funktion aufgerufen werden. Trotzdem sollten solche Funktionen einen charakteristischen Namen haben, da sie im globalen Namensraum verfügbar sind. Das heißt, sie können von überall innerhalb des Skripts aufgerufen werden.

Wenn einen Bibliotheksfunktion den #Include Befehl nutzt, ist das Arbeitsverzeichnis (working directory) von #Include das Verzeichis der Bibliotheksfunktion. Das kann dazu genutzt werden, einen Verweis auf eine größere Bibliothek zu erstellen, welche diese oder zugehörige Funktion beherbergt.

Der Skriptkompiler (ahk2exe) unterstützt ebenfalls Bibliotheksfunktionen. Das erfordert allerdings, dass eine Kopie der Autohotkey.exe im Verzeichnis überhalb des Kompilerverzeichnisses existiert (normalerweise der Fall). Falls die Autohotkey.exe fehlt, funktioniert der Kompiler zwar noch, Bibliotheksfunktionen werden aber nicht mehr automatisch eingebunden.

Funktionen, welche aus einer Bibliothek eingebunden werden, arbeiten genauso schnell wie andere Funktionen, da sie vor Ausführung des Skripts vorgeladen werden.

Bereitgestellte Funktionen

Optionale Parameter am Ende der Parameterliste von durch Autohotkey bereitgestellten Funktionen können bei Bedarf weggelassen werden. Beispiel WinExist("Unbenannt - Editor") ist syntaktisch korrekt, da die anderen drei Parameter leer übergeben werden können.

Eine durch Autohotkey bereitgestellte Funktion wird durch eine gleichnamige Funktion überschrieben, wenn sie den gleichen Namen zugewiesen bekommt. Ein Skript kann beispielsweise seine eigene, benutzerdefinierte WinExist() Funktion bereitstellen, die dann anstelle der Standardfunktion aufgerufen wird.

Externe Funktionen z.B. aus Dll Dateien können per DllCall() aufgerufen werden.

Oft genutzte Funktionen

FileExist(FilePattern): Liefert ein leeres Ergebnis (leere Zeichenfolge) zurück, wenn FilePattern nicht existiert (FilePattern wird in A_WorkingDir vermutet, wenn kein absoluter Pfad angegeben ist). Andernfalls liefert sie die Attributszeichenfolge (eine Teilmenge von "RASHNDOCT") der ersten gefundenen Datei oder des ersten gefundenen Ordners zurück. Wenn die Datei keine Attribute besitzt (sehr selten), wird "X" als Wert zurückgeliefert. FilePattern sollte der exakte Name einer Datei oder eines Ordners sein. Es kann aber auch wildcards (* oder ?) enthalten. Da eine leere Zeichenfolge als "false" angesehen wird, kann der Rückgabewert der Funktion als Quasi-Boolscher Wert angesehen werden. Die Zeile if FileExist("C:\My File.txt") wäre zum Beispiel "true" (wahr), wenn die Datei existiert und andernfalls "false" (unwahr). Ähnlich die nächste Zeile if InStr(FileExist("C:\My Folder"), "D"). Diese wäre nur dann wahr, wenn die Datei existiert und ein Ordner wäre. Dazugehörige Befehle: IfExist und FileGetAttrib.

GetKeyState(KeyName [, "P" oder "T"]): Im Gegensatz zum GetKeyState Befehl, der für eine gedrückte Taste D und eine losgelassene Taste U zurückliefert, gibt diese Funktion true (1) für eine gedrückte und false (0) für eine losgelassene Taste zurück. Wenn KeyName ungültig ist, wird eine leere Zeichenfolge zurückgegeben. Andere Rückgabewerte und Einsatzinstruktionen finden Sie in der Dokumentation zum GetKeyState Befehl.

InStr(Haystack, Needle [, CaseSensitive = false, StartingPos = 1]): Liefert die Position des ersten Auftretens der Needle Zeichenkette (string) innerhalb der Haystack Zeichenkette. Im Gegensatz zum StringGetPos Befehl entspricht die Position 1 dem ersten Zeichen. Und zwar aus dem Grund, weil 0 ein Synonym für "false" ist, und damit prädestiniert, für einen "not found" Indikator. Wenn der Parameter CaseSensitive weggelassen wird bzw. false ist, spielt die Groß-/Kleinschreibung bei der Suche keine Rolle (die Art und Weise der Insensitivität hängt vom StringCaseSense ab). Andernfalls muss die Groß- und Kleinschreibung exakt übereinstimmen. Wenn StartingPos weggelassen wird, ist ihr Standardwert 1 (der Anfang der Haystack Zeichenkette). Andernfalls vergeben Sie den Wert 2, um am zweiten Buchstaben von Haystack mit der Suche zu beginnen. Bei 3 starten Sie mit dem dritten Buchstaben, und so weiter. Wenn StartingPos außerhalb von Haystack liegt, wird der Wert 0 zurückgegeben. Wenn StartingPos 0 ist, wird die Suche rückwärts (von rechts nach links) durchgeführt. Dann wird der erste Treffer von rechts zurückgemeldet. Unabhängig vom Wert von StartingPos ist der zurückgebene Wert immer ein relativer Wert bezogen auf das erste Zeichen von Haystack. Die Position "abc" innerhalb der Zeichenfolge "123abc789" ist beispielsweise immer 4. Verwandte Befehle: RegExMatch(), IfInString, und StringGetPos.

RegExMatch(Haystack, NeedleRegEx [, UnquotedOutputVar = "", StartingPos = 1]): Details unter RegExMatch().

RegExReplace(Haystack, NeedleRegEx [, Replacement = "", OutputVarCount = "", Limit = -1, StartingPos = 1]): Details unter RegExReplace().

SubStr(String, StartingPos [, Length]) [v1.0.46+]: Kopiert eine Teilzeichenkette aus String. Begonnen wird an der StartingPos und dann nach rechts fortgesetzt, bis Length erfüllt ist (Wenn Length weggelassen wird, heißt das "alle Zeichen" kopieren). Um am ersten Zeichen zu beginnen, geben Sie für StartingPos die Zahl 1 an, die Zahl 2 für das zweite Zeichen und so weiter (Wenn die StartingPos außerhalb der Länge von String liegt, wird eine leere Zeichenkette zurückgeliefert). Wenn die StartingPos kleiner als 1 ist, wird sie als Offset vom Ende der Zeichenkette interpretiert. Die Zahl 0 extrahiert beispielsweise das letzte Zeichen, -1 die letzten beiden Zeichen der Zeichenkette (wenn StartingPos über das linke Ende der Zeichenkette hinausgeht, beginnt die Extrahierung am ersten Zeichen der Zeichenkette). Length steht für die maximale Anzahl an Zeichen, die extrahiert werden soll (wenn der verbleibende Teil der Zeichenkette zu kurz ist, wird nicht die maximale Anzahl an Zeichen zurückgeliefert). Mit Hilfe einer negativen Length können Sie die angegebene Anzahl an Zeichen vom Ende der zurückgelieferten Zeichenkette entfernen (werden alle oder zuviele Zeichen entfernt, wird eine leere Zeichenkette zurückgeliefert). Verwandte Befehle: RegExMatch(), StringMid, StringLeft/Right, StringTrimLeft/Right.

StrLen(String): Gibt die Länge von String zurück. Wenn String eine Variable ist, der davor der Inhalt von ClipboardAll zugewiesen wurde, wird deren Gesamtgröße zurückgeliefert. Dazugehöriger Befehl: StringLen.

WinActive(WinTitle [, WinText, ExcludeTitle, ExcludeText]): Liefert die Unique ID (HWND) des aktiven Fensters zurück, wenn dieses den angegebenen Kriterien entspricht. Falls nicht, meldet die Funktion den Wert 0 zurück. Da alle von 0 verschiedenen Zahlen als "true" angesehen werden, ist das Statement if WinActive("WinTitle") true, wenn WinTitle aktiv ist. WinTitle unterstützt ahk_id, ahk_class und andere spezielle Zeichenketten. Nähere Angaben zu diesen Zeichenketten und anderen Aspekten der Fensteraktivierung finden sie in der Dokumentation zum IfWinActive Befehl.

WinExist(WinTitle [, WinText, ExcludeTitle, ExcludeText]): Liefert die Unique ID (HWND) des zuerst gefundenen Fensters als hexadezimalen Integerwert zurück, wenn es den angegebenen Kriterien entspricht (0 wenn keines gefunden wird). Da alle von 0 verschiedenen Zahlen als "true" angesehen werden, ist das Statement if WinExist("WinTitle") true, wenn WinTitle existiert. WinTitle unterstützt ahk_id, ahk_class und andere spezielle Zeichenketten. Nähere Angaben zu diesen Zeichenketten und anderen Aspekten der Fenstersuche finden sie in der Dokumentation zum IfWinExist Befehl.

Verschiedene Funktionen

Asc(String): Liefert den ASCII Code (eine Zahl zwischen 1 und 255) für den ersten Buchstaben von String zurück. Wenn String leer ist, wird 0 zurückgeliefert.

Chr(Number): Liefert den Buchstaben der dem ASCII Code in Number entspricht. Wenn Number nicht zwischen 0 und 255 liegt, wird eine leere Zeichenkette zurückgeliefert. Gebräuchliche ASCII Codes sind 9 (tab), 10 (linefeed), 13 (carriage return), 32 (space), 48-57 (die Zahlen von 0-9), 65-90 (Großbuchstaben von A-Z) und 97-122 (Kleinbuchstaben von a-z).

DllCall(): Näheres unter DllCall().

IsLabel(LabelName): Gibt einen Wert verschieden von 0 aus, wenn LabelName im Skript als Subroutine, Hotkey oder Hotstring exisitiert (Die angehängten Doppelpunkte nicht in LabelName mit einfügen). Das Statement if IsLabel(VarContainingLabelName) wäre zum Beispiel true, wenn das Label existiert und andernfalls false. Dies ist zum Beispiel nützlich, um Laufzeitfehler in Befehlen wie Gosub, Hotkey, Menu und Gui abzufangen, wenn man ein dynamisches Label einsetzt.

ListView und TreeView Funktionen: Näheres in den Artikeln zu ListView und TreeView.

NumGet(VarOrAddress [, Offset = 0, Type = "UInt"]) [v1.0.47+]: Liefert die Binärzahl, die an der angegebenen Adresse+Offset abgelegt ist. Bei VarOrAddress ist die Übergabe von MyVar oder &MyVar völlig gleichwertig. Der Verzicht auf "&" ist allerdings performanter und stellt sicher, dass die Zieladresse gültig ist (Ungültige Addressen liefern "" zurück). Im Gegensatz dazu jede nicht reine Variable die als VarOrAddress übergeben wird als eine direkte Adressangabe (raw address) behandelt; bei einer Angabe wie MyVar+0 wird deswegen als Konsequenz daraus die in MyVar abgelegte Nummer statt der Adresse von MyVar verwendet. Als Type verwendet man UInt, Int, Int64, Short, UShort, Char, UChar, Double, oder Float (Im Gegensatz zu DllCall, müssen diese in Anführungszeichen gesetzt werden, wenn sie als literale Zeichenketten verwendet werden); Näheres unter DllCall Types.

NumPut(Number, VarOrAddress [, Offset = 0, Type = "UInt"]) [v1.0.47+]: Speichert Number im Binärformat an der angegebenen Adresse+Offset und liefert die Adresse rechts vom gerade geschriebenen Objekt. Bei VarOrAddress ist die Übergabe von MyVar oder &MyVar völlig gleichwertig. Der Verzicht auf "&" ist allerdings performanter und stellt sicher, dass die Zieladresse gültig ist (Ungültige Addressen liefern "" zurück). Im Gegensatz dazu jede nicht reine Variable die als VarOrAddress übergeben wird als eine direkte Adressangabe (raw address) behandelt; bei einer Angabe wie MyVar+0 wird deswegen als Konsequenz daraus die in MyVar abgelegte Nummer statt der Adresse von MyVar verwendet. Als Type verwendet man UInt, Int, Int64, Short, UShort, Char, UChar, Double, oder Float (Im Gegensatz zu DllCall, müssen diese in Anführungszeichen gesetzt werden, wenn sie als literale Zeichenketten verwendet werden); Näheres unter DllCall Types. Wenn eine Integer-Zahl zu groß für den angegebenen Typ ist, werden die höchstwertigen Bytes ignoriert; z. B. würde NumPut(257, var, 0, "Char") die Zahl 1 speichern.

OnMessage(MsgNumber [, "FunctionName"]): Überwacht eine Message/ein Event. Näheres unter OnMessage().

RegisterCallback(): Näheres unter RegisterCallback().

VarSetCapacity(UnquotedVarName [, RequestedCapacity, FillByte]): Erhöht die Speichergröße einer Variable oder gibt ihren Speicher wieder frei. Näheres unter VarSetCapacity().

Allgemeine Mathematik

Bemerkung: Die mathematischen Funktionen liefern immer ein leeres Ergebnis (leere Zeichenkette) zurück, wenn einer der Input Parameter nicht-numerisch ist.

Abs(Number): Gibt den absoluten Wert von Number zurück. Der Rückgabewert besitzt den selben Typ, wie Number (Integer oder Gleitkomma).

Ceil(Number): Gibt Number aufgerundet auf den nächsten Integerwert (ohne .00 Suffix) zurück. Ceil(1.2) ergibt beispielsweise 2, Ceil(-1.2) ergibt -1.

Exp(N): Liefert die N-te Potenz von e (ungefähr 2.71828182845905). N kann negativ sein und darf auch ein Komma enthalten. Um andere Zahlen als e zu potenzieren, verwenden Sie einfach den ** Operator.

Floor(Number): Gibt Number abgerundet auf den nächsten Integerwert (ohne .00 Suffix) zurück. Floor(1.2) ergibt beispielsweise 1, Floor(-1.2) ergibt -2

Log(Number): Liefert den Logarithmus (Basis 10) von Number. Das Ergebnis ist vom Typ floating point (Gleitkommazahl). Wenn Number negativ ist, wird ein leeres Ergebnis ausgegeben.

Ln(Number): Liefert den Logarithmus naturalis (Basis e) von Number. Das Ergebnis ist vom Typ floating point (Gleitkommazahl). Wenn Number negativ ist, wird ein leeres Ergebnis ausgegeben.

Mod(Dividend, Divisor): Modulo. Liefert den Rest, wenn Dividend durch den Divisor geteilt wird. Das Vorzeichen des Ergebnisses entspricht dem Vorzeichen des ersten Parameters. Mod(5, 3) und Mod(5, -3) liefern beispielweise beide als Ergebnis 2, Mod(-5, 3) und Mod(-5, -3) dagegen beide -2. Wenn einer der beiden Parameter eine Gleitkommazahl (floating point number) ist, ist das Ergebnis ebenfalls eine Gleitkommazahl. Mod(5.0, 3) ist beispielsweise 2.0, Mod(5, 3.5) ergibt 1.5. Wenn der zweite Parameter 0 ist, liefert die Funktion ein leeres Ergebnis (leere Zeichenkette).

Round(Number [, N]): Wenn N weggelassen wird, oder 0 ist, wird Number auf den nächsten Integerwert gerundet. Wenn N eine positive Zahl ist, wird Number auf N Dezimalstellen gerundet. Wenn N negativ ist, wird Number um N Stellen links vom Komma gerundet. Round(345, -1) ergibt beispielsweise 350, Round(345, -2) dagegen 300. Im Gegensatz zu Transform Round besitzt das Ergebnis keinen .000 Suffix, wenn N weggelassen wird, oder kleiner als 1 ist. Ab Version v1.0.44.01+ hat ein Wert, wenn N größer als 0 ist, auf alle Fälle N Dezimalstellen, anstatt sich nach SetFormat zu richten. Wenn Sie dieses Problem umgehen wollen, führen Sie einfach eine weitere mathematische Operation mit dem Rückgabewert von Round() durch. Beispiel: Round(3.333, 1)+0.

Sqrt(Number): Liefert die Quadratwurzel von Number. Das Ergebnis ist vom Typ floating point (Gleitkommazahl). Wenn Number negativ ist, wird ein leeres Ergebnis ausgegeben.

Trigonometrie

Sin(Number) | Cos(Number) | Tan(Number) : Liefert den trigonometrischen Sinus|Cosinus|Tangens von Number. Number muss als Bogenmaß angegeben werden.

ASin(Number): Liefert den Arcussinus (die Zahl, dessen Sinus Number entspricht) als Bogenmaß. Wenn Number kleiner als -1 oder größer als 1 ist, gibt die Funktion ein leeres Ergebnis (leere Zeichenkette) zurück.

ACos(Number): Liefert den Arcuscosinus (die Zahl, dessen Cosinus Number entspricht) als Bogenmaß. Wenn Number kleiner als -1 oder größer als 1 ist, gibt die Funktion ein leeres Ergebnis (leere Zeichenkette) zurück.

ATan(Number): Liefert den Arcustangens (die Zahl, dessen Tangens Number entspricht) als Bogenmaß.

Anmerkung: Um ein Bogenmaßwert in einen Gradwert zu konvertieren, multiplizieren Sie in einfach mit 180/Pi (ungefähr 57.29578). Um einen Gradwert in ein Bogenmaß zu konvertieren, multiplizieren Sie ihn einfach mit Pi/180 (ungefähr 0.01745329252). Der Wert von Pi (ungefähr 3.141592653589793) entspricht dem vierfachen Arcustangens von 1.

Andere Funktionen

Titan's Befehlsfunktionen: Der User Titan aus dem englischen Forum stellt aufrufbare Funktionen für jeden Autohotkey Befehl zur Verfügung, der über eine OutputVar verfügt. Diese Bibliothek (library) kann mit Hilfe der #Include Direktive in die eigenen Skripte eingebaut werden.