Funktionen

Inhaltsverzeichnis

Einführung und einfache Beispiele

Eine Funktion ist so etwas Ähnliches wie eine Subroutine (GoSub), allerdings mit dem Unterschied, dass eine Funktion zusätzlich mit Parametern (Eingabewerten) aufgerufen werden kann. Eine Funktion kann auch direkt einen Wert an ihren Aufrufer zurückgeben. Das folgende Beispiel ist eine einfache Funktion, die zwei Zahlen akzeptiert und deren Summe zurückgibt:

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

So etwas nennt man auch eine Funktionsdefinition, weil es eine Funktion mit dem Namen "Addieren" erstellt (nicht Groß-/Kleinschreibung-sensitiv) und festlegt, dass jeder, der die Funktion aufruft, genau zwei Parameter (x und y) bereitstellen muss. Um die Funktion aufzurufen, weisen Sie ihr Ergebnis einer Variable mit dem Doppelpunkt-Gleich-Operator (:=) zu. Zum Beispiel:

Var := Addieren(2, 3)  ; Speichert die Zahl 5 in Var.

Eine Funktion kann auch aufgerufen werden, ohne ihren Rückgabewert zu speichern:

Addieren(2, 3)

In diesem Fall wird jedoch der Rückgabewert der Funktion verworfen; diese Art des Aufrufs ist nur dann sinnvoll, wenn die Funktion einen anderen Effekt als ihren Rückgabewert hat.

Da ein Funktionsaufruf ein Ausdruck ist, sollten die Variablennamen in der Parameterliste nicht mit Prozentzeichen umschlossen werden. Außerdem müssen direkt geschriebene Zeichenketten in doppelte Anführungszeichen gesetzt werden. Zum Beispiel:

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

Es ist möglich, Funktionen innerhalb der Parameter eines Befehls aufzurufen (außer in EingabeVar- und AusgabeVar-Parametern, wie die von StringLen). Allerdings müssen Sie bei Parametern, die keine Ausdrücke unterstützen, das Präfix "% " verwenden. Zum Beispiel:

MsgBox % "Das Ergebnis ist: " . Addieren(3, 2)

Das Präfix "% " ist auch in Parametern zulässig, die standardmäßig Ausdrücke unterstützen, aber dann wird es einfach ignoriert.

Parameter

Beim Definieren einer Funktion werden ihre Parameter in runden Klammern rechts neben ihrem Namen aufgelistet (zwischen dem Namen und der runden Startklammer sind keine Leerzeichen erlaubt). Wenn die Funktion keine Parameter akzeptiert, kann der Inhalt zwischen den runden Klammern leer gelassen werden, z.B. ErmittleAktuellenZeitstempel().

ByRef-Parameter: Innerhalb der Funktion werden Parameter grundsätzlich als lokale Variablen behandelt, es sei denn, sie werden wie im folgenden Beispiel als ByRef-Parameter definiert:

Tauschen(ByRef Links, ByRef Rechts)
{
    temp := Links
    Links := Rechts
    Rechts := temp
}

Das ByRef oben macht den Parameter zu einem Pseudonym für die vom Aufrufer übergebene Variable. Mit anderen Worten, der Parameter und die Variable des Aufrufers verweisen auf denselben Inhalt im Speicher. Auf diese Weise kann die Tauschen-Funktion die Variablen des Aufrufers ändern, indem sie den Inhalt der Links-Variable in die Rechts-Variable verschiebt, und umgekehrt.

Ohne ByRef wären Links und Rechts dagegen nur Kopien der Variablen des Aufrufers - die Tauschen-Funktion hätte keine externe Wirkung.

ByRef kann als Ergänzung zu Return verwendet werden, um mehr als einen Wert zurückzugeben. Dazu muss der Aufrufer eine Variable übergeben (üblicherweise leer), in der die Funktion einen Wert speichern kann.

Die Übergabe von langen Zeichenketten an eine Funktion via ByRef ist performanter und verhindert, dass die Zeichenketten doppelten Speicherplatz verbrauchen, weil von ihnen eine Kopie erstellt werden muss. Auch die Rückgabe von langen Zeichenketten an den Aufrufer via ByRef ist in der Regel performanter als z.B. Return LangeZeichenkette.

[AHK_L 60+]: Übergibt man eine schreibgeschützte Variable an einen ByRef-Parameter, verhält sich die Funktion so, als wäre das Schlüsselwort "ByRef" nicht vorhanden. Zum Beispiel speichert Tauschen(A_Index, i) den Wert von A_Index in i, allerdings wird der Wert von Links wieder verworfen, wenn die Tauschen-Funktion fertig ist.

[v1.1.01+]: Mit der IsByRef-Funktion kann geprüft werden, ob der Aufrufer eine Variable für einen bestimmten ByRef-Parameter bereitgestellt hat.

Bekannte Einschränkungen:

Optionale Parameter

Beim Definieren einer Funktion können beliebig viele Parameter als optional gekennzeichnet werden. Fügen Sie einfach nach dem Parameter ein := (in [v1.1.09+]) oder = an, gefolgt vom gewünschten Standardwert, der Folgendes sein kann: True, False, ein direkt geschriebener Integer, eine direkt geschriebene Floating-Point-Zahl oder eine direkt geschriebene, in Anführungszeichen gesetzte Zeichenkette wie "fox" oder "" (vor [v1.0.46.13] war nur "" möglich).

Die Verwendung von = (ohne Doppelpunkt) ist aus Gründen der Abwärtskompatibilität erlaubt, wird aber nicht empfohlen, da es in AutoHotkey v2 nicht mehr zugelassen ist. Unabhängig vom verwendeten Operator müssen Standardwerte, die Zeichenketten sind, immer in Anführungszeichen gesetzt werden.

Die folgende Funktion hat einen Z-Parameter, der als optional gekennzeichnet ist:

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

Ruft man die Funktion mit drei Parametern auf, wird der Standardwert von Z ignoriert. Ruft man die Funktion jedoch nur mit zwei Parametern auf, bekommt die Z-Variable automatisch den Wert 0 zugewiesen.

Es ist nicht möglich, optionale Parameter isoliert in der Mitte der Parameterliste anzugeben. Mit anderen Worten: Alle Parameter rechts vom ersten optionalen Parameter müssen ebenfalls als optional gekennzeichnet sein. [AHK_L 31+]: Optionale Parameter können in der Mitte der Parameterliste weggelassen werden, wenn die Funktion aufgerufen wird (siehe unten). In [v1.1.12+] gilt das auch für dynamische Funktionsaufrufe und Methodenaufrufe.

MeineFunk(1,, 3)
MeineFunk(X, Y:=2, Z:=0) {  ; Beachten Sie, dass Z in diesem Fall optional bleiben muss.
    MsgBox %X%, %Y%, %Z%
}

[v1.0.46.13+]: ByRef-Parameter können auch einen Standardwert haben, z.B. MeineFunk(ByRef p1 = ""). Wenn die Funktion ohne diesen Parameter aufgerufen wird, wird eine lokale Variable mit dem angegebenen Standardwert erstellt, d.h. die Funktion wird sich so verhalten, als würde das Schlüsselwort "ByRef" fehlen.

Werte an den Aufrufer zurückgeben

Wie bereits in der Einführung erwähnt, kann eine Funktion einen Wert via Return an ihren Aufrufer zurückgeben.

Test := returnTest()
MsgBox % Test

returnTest() {
    return 123
}

Wenn eine Funktion mehr als ein Ergebnis zurückgeben soll, können Sie auch ByRef verwenden:

returnByRef(A,B,C)
MsgBox % A "," B "," C

returnByRef(ByRef val1, ByRef val2, ByRef val3)
{
    val1 := "A"
    val2 := 100
    val3 := 1.1
    return
}

[v1.0.97+]: Sie können Objekte und Arrays verwenden, um mehrere Werte oder sogar benannte Werte zurückzugeben:

Test1 := returnArray1()
MsgBox % Test1[1] "," Test1[2]

Test2 := returnArray2()
MsgBox % Test2[1] "," Test2[2]

Test3 := returnObject()
MsgBox % Test3.id "," Test3.val

returnArray1() {
    Test := [123,"ABC"]
    return Test
}

returnArray2() {
    x := 456
    y := "EFG"
    return [x, y]
}

returnObject() {
    Test := {id: 789, val: "HIJ"}
    return Test
}

Variadische Funktionen [AHK_L 60+]

Beim Definieren einer Funktion können Sie den letzten Parameter mit einem Sternchen versehen, um die Funktion als variadisch zu kennzeichnen, wodurch ihr eine variable Anzahl von Parametern übergeben werden kann:

Verbinden(sep, params*) {
    for index,param in params
        str .= param . sep
    return SubStr(str, 1, -StrLen(sep))
}
MsgBox % Verbinden("`n", "eins", "zwei", "drei")

Beim Aufruf einer variadischen Funktion können überschüssige Parameter über ein Objekt abgerufen werden, das im letzten Parameter der Funktion gespeichert ist. Der erste überschüssige Parameter ist params[1], der zweite ist params[2] und so weiter. Dieses Objekt kann wie alle normalen Objekte params.MaxIndex() verwenden, um den höchsten numerischen Index zu ermitteln (in diesem Fall die Anzahl der Parameter). Wenn aber keine Parameter vorhanden sind, gibt MaxIndex eine leere Zeichenkette zurück.

Hinweise:

Variadische Funktionsaufrufe

Während variadische Funktionen eine variable Anzahl von Parametern akzeptieren, kann ein Array von Parametern an eine beliebige Funktion übergeben werden, indem die gleiche Syntax auf einen Funktionsaufruf angewendet wird:

TeilZketten := ["eins", "zwei", "drei"]
MsgBox % Verbinden("`n", TeilZketten*)

Hinweise:

Bekannte Einschränkungen:

Lokale und globale Variablen

Lokale Variablen

Lokale Variablen sind funktionsspezifisch und nur innerhalb dieser Funktion sichtbar. Folglich kann eine lokale Variable, die denselben Namen wie eine globale Variable hat, etwas anderes enthalten als die globale Variable. Verschiedene Funktionen können ohne Bedenken die gleichen Variablennamen benutzen.

Alle lokalen Variablen, die nicht statisch sind, werden nach Abschluss der Funktion automatisch freigegeben (leer gemacht).

Interne Variablen wie Clipboard, ErrorLevel und A_TimeIdle sind nie lokal (sie sind von überall zugänglich) und können nicht neu deklariert werden.

Funktionen sind standardmäßig im Assume-Local-Modus. Variablen, die innerhalb einer Assume-Local-Funktion verwendet oder erstellt werden, sind standardmäßig lokal, aber es gibt folgende Ausnahmen:

Siehe unten, wie das Standardverhalten überschrieben werden kann (indem man die Variable deklariert oder den Modus der Funktion ändert).

Force-Local-Modus [v1.1.27+]: Wenn die erste Zeile der Funktion das Wort "local" ist, werden alle Variablenreferenzen (auch dynamische) als lokal vermutet, es sei denn, sie werden innerhalb der Funktion als global deklariert. Im Gegensatz zum Standardmodus verhält sich der Force-Local-Modus wie folgt:

Globale Variablen

Um innerhalb einer Funktion auf eine bestehende globale Variable zu verweisen (oder eine neue zu erstellen), muss die Variable vor ihrer Verwendung als global deklariert werden. Zum Beispiel:

InDateiLoggen(ZuLoggenderText)
{
    global LogDateiName  ; Diese globale Variable bekam bereits außerhalb dieser Funktion einen Wert zugewiesen.
    FileAppend, %ZuLoggenderText%`n, %LogDateiName%
}

Assume-Global-Modus: Wenn eine Funktion viele globale Variablen verwenden oder erstellen muss, kann die Funktion so definiert werden, dass sie alle ihre Variablen (außer ihren Parametern) global behandelt. Dazu muss in ihrer ersten Zeile entweder das Wort "global" oder die Deklaration einer lokalen Variable stehen. Zum Beispiel:

StandardwerteSetzen()
{
    global  ; Kann weggelassen werden, wenn die erste Zeile so etwas wie "local MeineVar" ist.
    GlobaleVar := 33  ; Speichert 33 in eine globale Variable und erstellt vorher sie bei Bedarf.
    local x, y:=0, z  ; Lokale Variablen müssen in diesem Modus deklariert werden, sonst werden sie global behandelt.
}

Dieser Assume-Global-Modus kann auch von einer Funktion verwendet werden, um ein globales Array zu erstellen - z.B. eine Schleife, die Werte in Array%A_Index% speichert.

Superglobale Variablen [v1.1.05+]: Wenn eine globale Deklaration außerhalb einer Funktion erfolgt, wird sie standardmäßig für alle Funktionen (außer Force-Local-Funktionen) wirksam. Dadurch entfällt die Notwendigkeit, die Variable in jeder Funktion neu zu deklarieren. Beachten Sie aber, dass ein Funktionsparameter oder eine lokale Variable mit demselben Namen Vorrang vor der globalen Variable hat. Variablen, die mit dem Schlüsselwort class erzeugt wurden, sind ebenfalls superglobal.

Statische Variablen

Statische Variablen sind immer implizit lokal, unterscheiden sich aber von lokalen Variablen, da ihre Werte zwischen den Aufrufen gespeichert werden. Zum Beispiel:

InDateiLoggen(ZuLoggenderText)
{
    static GeloggteZeilen := 0
    GeloggteZeilen += 1  ; Behält einen Zähler lokal aufrecht (sein Wert wird zwischen den Aufrufen gespeichert).
    global LogDateiName
    FileAppend, %GeloggteZeilen%: %ZuLoggenderText%`n, %LogDateiName%
}

Statische Initialisierungen: In den Versionen vor v1.0.46 starteten alle statischen Variablen mit einem leeren Wert; um also zu erkennen, ob statische Variablen zum ersten Mal verwendet wurden, musste man überprüfen, ob sie leer waren. [v1.0.46+]: Es ist möglich, eine statische Variable bei ihrer Deklaration mit etwas anderem als "" zu initialisieren. Fügen Sie einfach nach dem Variablennamen den Operator := oder = an, gefolgt von einem der folgenden Werte: True, False, ein direkt geschriebener Integer, eine direkt geschriebene Floating-Point-Zahl oder eine direkt geschriebene, in Anführungszeichen gesetzte Zeichenkette wie "fox". Zum Beispiel: static X:=0, Y:="fox". Jede statische Variable wird nur einmal initialisiert (vor Beginn der Skriptausführung).

[AHK_L 58+]: static Var := Ausdruck wird unterstützt. Alle Ausdrücke dieser Art werden unmittelbar vor dem automatischen Ausführungsbereich des Skripts ausgewertet - in der Reihenfolge, wie sie im Skript vorkommen.

Assume-Static-Modus [v1.0.48+]: Eine Funktion kann so definiert werden, dass sie alle ihre Variablen (außer ihren Parametern) statisch behandelt. Dazu muss in ihrer ersten Zeile das Wort "static" stehen. Zum Beispiel:

VomStatischenArrayAbrufen(ElementNummer)
{
    static
    static ErsterAufruf := true  ; Die Initialisierung einer statischen Deklaration wird nur einmal ausgeführt (beim Start).
    if ErsterAufruf  ; Erstellt ein statisches Array beim ersten Aufruf, danach nicht mehr.
    {
        ErsterAufruf := false
        Loop 10
            StatischesArray%A_Index% := "Wert Nr. " . A_Index
    }
    return StatischesArray%ElementNummer%
}

Im Assume-Static-Modus muss jede Variable, die nicht statisch sein soll, als lokal oder global deklariert werden (mit den gleichen Ausnahmen wie im Assume-Local-Modus, es sei denn, der Force-Local-Modus ist ebenfalls aktiv).

[v1.1.27+]: Der Force-Local-Modus kann mit dem Assume-Static-Modus kombiniert werden, indem man local und dann static angibt, wie unten gezeigt. Die Funktion verwendet dadurch Force-Local-Regeln, erstellt aber standardmäßig statische Variablen.

global MeineVar := "Das ist global"
ForceStaticDemonstrieren()

ForceStaticDemonstrieren()
{
    local
    static
    MeineVar := "Dies ist statisch"
    ListVars
    MsgBox
}

Mehr zu lokalen und globalen Deklarationen

Es ist möglich, mehrere Variablen in derselben Zeile zu deklarieren. Trennen Sie sie wie folgt durch Kommas:

global LogDateiName, MaxVersuche := 5
static GesamtVersuche := 0, VorherErgebnis

[v1.0.46+]: Es ist möglich, eine lokale oder globale Variable bei ihrer Deklaration zu initialisieren. Fügen Sie einfach nach dem Variablennamen den Operator := oder = an, gefolgt von einem beliebigen Ausdruck (der =-Operator verhält sich in Deklarationen wie :=). Im Gegensatz zu statischen Initialisierungen werden lokale und globale Initialisierungen bei jedem Funktionsaufruf ausgeführt, sofern der Kontrollfluss sie tatsächlich erreicht. Mit anderen Worten, eine Zeile wie local x := 0 hat den gleichen Effekt wie, als würde man zwei einzelne Zeilen schreiben: local x, gefolgt von x := 0.

Da die Wörter local, global und static sofort beim Start des Skripts verarbeitet werden, kann eine Variable nicht bedingt unter Nutzung einer IF-Anweisung deklariert werden. Mit anderen Worten, eine Deklaration innerhalb eines IF- oder ELSE-Blocks wirkt sich auf alle Zeilen zwischen der Deklaration und der geschweiften Endklammer der Funktion aus. Beachten Sie auch, dass es zur Zeit nicht möglich ist, eine dynamische Variable zu deklarieren, wie z.B. global Array%i%.

Bei Befehlen, die Pseudo-Arrays erzeugen (z.B. StringSplit), ist jede Variable im resultierenden Pseudo-Array lokal, wenn der Assume-Global-Modus nicht aktiv ist oder wenn das erste Pseudo-Array-Element als lokale Variable deklariert wurde (dies gilt auch, wenn einer der Funktionsparameter übergeben wurde - selbst wenn dieser Parameter ByRef ist - da Parameter ähnlich wie lokale Variablen sind). Umgekehrt wird ein globales Array erzeugt, wenn das erste Element global deklariert wurde. Beachten Sie, dass hierbei der unten erwähnte Häufige Anlass zu Verwirrung berücksichtigt werden muss. Das erste erzeugte Element von StringSplit ist ArrayName0. Das erste erzeugte Element von anderen array-erstellenden Befehlen wie WinGet List ist ArrayName (also ohne Nummer). [v1.1.27+]: Wenn der Force-Local-Modus aktiv ist, folgen diese Befehle den gleichen Regeln wie normale Variablenreferenzen, d.h. jedes Pseudo-Array-Element, das nicht als global deklariert ist, wird lokal sein, auch wenn andere Elemente als global deklariert sind.

Innerhalb einer Funktion (sofern der Force-Local-Modus nicht aktiv ist) wird jede dynamische Variablenreferenz wie Array%i% in eine lokale Variable aufgelöst, es sei denn, es existiert keine Variable mit diesem Namen, dann wird eine globale Variable verwendet, sofern vorhanden. Wenn weder eine lokale noch globale Variable vorhanden ist und die Nutzung erfordert, dass die Variable erstellt sein muss, wird sie als lokale Variable erstellt, solange der Assume-Global-Modus nicht aktiv ist. Eine Funktion kann also nur dann ein globales Array erstellen (z.B. via Array%i% := A_Index), wenn der Assume-Global-Modus aktiv ist.

Häufiger Anlass zu Verwirrung: Jede nicht-dynamische Referenz zu einer Variable bewirkt, dass diese Variable beim Start des Skripts erstellt wird. Außerhalb einer Funktion bewirkt bspw. eine Anweisung wie MsgBox %Array1%, dass beim Start des Skripts eine globale Variable namens Array1 erstellt wird. Innerhalb einer Funktion hingegen bewirkt eine Anweisung wie MsgBox %Array1%, dass beim Start des Skripts eine funktionsspezifische lokale Variable mit dem Namen Array1 erstellt wird (sofern der Assume-Global-Modus nicht aktiv ist), auch dann, wenn Array und Array0 als global deklariert sind.

Funktionen dynamisch aufrufen

[v1.0.47.06+]: Eine Funktion (auch eine interne Funktion) kann dynamisch via Prozentzeichen aufgerufen werden. Zum Beispiel würde %Var%(x, "Fuchs") die Funktion aufrufen, deren Name in Var enthalten ist. Funk%A_Index%() wiederum würde Funk1(), Funk2() usw. aufrufen, je nachdem, welcher Wert gerade in A_Index enthalten ist.

[v1.1.07.00+]: Var in %Var%() kann einen Funktionsnamen oder ein Funktionsobjekt enthalten. Falls die Funktion nicht existiert, wird stattdessen die __Call-Metafunktion des Standardbasisobjekts indirekt aufgerufen.

Wenn die Funktion aus einem der folgenden Gründe nicht aufgerufen werden kann, wird die Auswertung des Ausdrucks, der den Aufruf enthält, ohne Fehlermeldung vorzeitig gestoppt, was zu inkonsistenten Ergebnissen führen kann:

Beachten Sie, dass ein dynamischer Aufruf etwas langsamer ist als ein normaler Aufruf, weil normale Aufrufe aufgelöst (nachgeschlagen) werden, bevor das Skript mit der Ausführung beginnt.

Boolesche Kurzschlussauswertung

AND, OR und der ternäre Operator innerhalb eines Ausdrucks reduzieren die Auswertung auf ein Minimum, um die Performanz zu erhöhen (egal ob Funktionsaufrufe vorhanden sind oder nicht). Beim Kurzschließen werden nur Bereiche des Ausdrucks ausgewertet, die Einfluss auf das Endergebnis haben. Das folgende Beispiel zeigt, wie das genau funktioniert:

if (FarbeName != "" AND not FindeFarbe(FarbeName))
    MsgBox %FarbeName% konnte nicht gefunden werden.

Im Beispiel oben wird die FindeFarbe()-Funktion nie aufgerufen, wenn die FarbeName-Variable leer ist, weil die Auswertung der linken Seite von AND False ergibt, wodurch die rechte Seite nicht mehr in der Lage wäre, das Endergebnis auf True zu bringen.

Dieses Verhalten führt dazu, dass die Nebeneffekte einer Funktion (wie z.B. die Änderung des Inhalts einer globalen Variable) nie auftreten werden, wenn diese Funktion auf der rechten Seite von AND oder OR aufgerufen wird.

Beachten Sie auch, dass die Kurzschlussauswertung verschachtelte ANDs und ORs stufenweise abarbeitet. Wenn z.B. FarbeName im folgenden Ausdruck leer ist, wird nur der Vergleich ganz links durchgeführt, weil die linke Seite dann ausreichen würde, um das Endergebnis zweifelsfrei zu bestimmen:

if (FarbeName = "" OR FindeFarbe(FarbeName, Region1) OR FindeFarbe(FarbeName, Region2))
    break   ; Nichts zu suchen oder Übereinstimmung gefunden.

Wie die Beispiele oben zeigen, sollten umfangreiche (zeitaufwendige) Funktionen in der Regel auf der rechten Seite von AND oder OR aufgerufen werden, um die Performanz zu erhöhen. Diese Technik kann auch verwendet werden, um den Aufruf einer Funktion zu verhindern, wenn ihr ein Wert übergeben wurde, den sie für unpassend hält (z.B. eine leere Zeichenkette).

[v1.0.46+]: Der ternäre Bedingungsoperator (?:) wendet auch die Kurzschlussauswertung an, indem er nur die gewinnende Abzweigung auswertet.

Subroutinen innerhalb von Funktionen

Eine Funktion kann Subroutinen enthalten, aber keine Definitionen anderer Funktionen. Sie können wie alle Subroutinen via GoSub gestartet und via Return beendet werden (in diesem Fall gilt das Return nicht für die Funktion, sondern für das GoSub).

Bekannte Einschränkung: Momentan darf der Name jeder Subroutine (Label) nur einmal im gesamten Skript vorkommen. Das Programm wird Sie darauf hinweisen, wenn ein Label doppelt vorhanden ist.

Wenn eine Funktion GoSub verwendet, um zu einer öffentlichen Subroutine zu springen (also zu einer, die sich außerhalb der geschweiften Klammern der Funktion befindet), sind alle externen Variablen global und die lokalen Variablen der Funktion erst wieder zugänglich, wenn die Subroutine ihr Ende erreicht hat. Allerdings wird A_ThisFunc weiterhin den Namen der Funktion enthalten.

Ein Goto kann nicht verwendet werden, um innerhalb einer Funktion zu einer externen Subroutine zu springen, allerdings kann eine Funktion via Gosub zu einer externen Subroutine springen und von dort aus ein Goto durchführen.

Trotz seines schlechten Rufs ist ein Goto nützlich, um z.B. innerhalb einer Funktion auf eine andere Position zu springen. Dies kann zur Vereinfachung komplexer Funktionen beitragen, die mehrere Returns haben und vor einem Return aufgeräumt werden müssen.

Eine Funktion kann Subroutinen enthalten, die extern aufgerufen werden, wie z.B. Timer, g-Labels und Menüpunkte. Das wird in der Regel getan, um sie gesondert in einer separaten Datei unterzubringen, für die Verwendung mit #Include. Auf diese Weise kann verhindert werden, dass sie den automatischen Ausführungsbereich des Skripts stören. Allerdings gelten folgende Einschränkungen:

Return, Exit und allgemeine Bemerkungen

Wenn die Ausführung die geschweifte Endklammer der Funktion vor einem Return erreicht, endet die Funktion und gibt einen leeren Wert (eine leere Zeichenkette) zurück. Ein leerer Wert wird auch zurückgegeben, wenn die Funktion den Parameter von Return explizit weglässt.

Wenn eine Funktion den Exit-Befehl zum Terminieren des aktuellen Threads verwendet, erhält ihr Aufrufer überhaupt keinen Rückgabewert. Das Var in Var := Addieren(2, 3) bliebe beispielsweise unverändert, wenn Addieren() via Exit beendet wird. Das gleiche passiert, wenn die Funktion einen Laufzeitfehler verursacht, wie z.B. das Ausführen einer nicht-existierenden Datei (nur wenn UseErrorLevel nicht aktiv ist).

Eine Funktion kann den Wert von ErrorLevel ändern, um einen zusätzlichen Wert zurückzugeben, der leicht zu merken ist.

Um eine Funktion mit einem oder mehreren leeren Werten (leeren Zeichenketten) aufzurufen, verwenden Sie zwei aufeinanderfolgende Anführungszeichen. Zum Beispiel: FindeFarbe(FarbeName, "").

Da der Aufruf einer Funktion keinen neuen Thread startet, wirken sich Änderungen an Einstellungen wie SendMode und SetTitleMatchMode auch auf den Aufrufer aus.

Der Aufrufer einer Funktion kann ihr eine nicht-existierende Variable oder einen nicht-existierenden Array-Element übergeben, was nützlich ist, wenn die Funktion erwartet, dass der entsprechende Parameter ByRef ist. Zum Beispiel würde der Aufruf von ErmittleNächsteZeile(LeeresArray%i%) automatisch die Variable LeeresArray%i% als lokale oder globale Variable erstellen (abhängig davon, ob sich der Aufrufer in einer Funktion befindet und ob der Assume-Global-Modus aktiv ist).

ListVars kann, wenn es in einer Funktion verwendet wird, die Namen und Inhalte von lokalen Variablen anzeigen. Dies kann helfen, ein Skript zu debuggen.

Stil- und Namenskonventionen

Bei komplexen Funktionen kann es hilfreich sein, spezielle Variablen mit eindeutigen Präfixen zu versehen, um die Übersichtlichkeit und Wartbarkeit des Skripts zu verbessern. Zum Beispiel können die Namen der Parameter einer Funktion mit "p" oder "p_" beginnen, damit die Parameter auf den ersten Blick leichter zu erkennen sind, insbesondere dann, wenn eine Funktion mehrere Dutzend lokale Variablen enthält. Ebenso kann das Präfix "r" oder "r_" für ByRef-Parameter und "s" oder "s_" für statische Variablen verwendet werden.

Je nach Bedarf kann der One True Brace (OTB) Style zum Definieren von Funktionen verwendet werden. Zum Beispiel:

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

Skripte mittels #Include auf dieselben Funktionen zugreifen lassen

Die #Include-Direktive kann verwendet werden (auch am Anfang eines Skripts), um Funktionen aus einer externen Datei zu laden.

Erklärung: Wenn die Skriptausführung eine Funktionsdefinition erreicht, wird diese übersprungen (was sofort passiert) und die Ausführung bei der Zeile nach der geschweiften Endklammer fortgesetzt. Folglich kann die Ausführung nie in eine Funktionsdefinition geraten. Außerdem haben eine oder mehrere Funktionsdefinitionen am Anfang eines Skripts keinen Einfluss auf den automatischen Ausführungsbereich.

Funktionsbibliotheken: Standard- und Benutzerbibliothek [v1.0.47+]

Ein Skript kann eine Funktion in einer externen Datei aufrufen, ohne #Include verwenden zu müssen. Damit dies funktioniert, muss eine Datei mit dem gleichen Namen wie die Funktion in einem der folgenden Bibliotheksverzeichnisse vorhanden sein:

%A_ScriptDir%\Lib\  ; Lokale Bibliothek - benötigt [AHK_L 42+].
%A_MyDocuments%\AutoHotkey\Lib\  ; Benutzerbibliothek.
Verzeichnis-der-aktuell-laufenden-AutoHotkey.exe\Lib\  ; Standardbibliothek.

Wenn ein Skript beispielsweise die nicht-existierende Funktion MeineFunk() aufruft, sucht das Programm in der Benutzerbibliothek nach einer Datei mit dem Namen "MeineFunk.ahk". Wenn sie dort nicht ist, wird die Standardbibliothek durchsucht. Wenn sie auch dort nicht gefunden wird und enthält der Funktionsname einen Unterstrich (z.B. MeinPräfix_MeineFunk), sucht das Programm in beiden Bibliotheken nach einer Datei mit dem Namen MeinPräfix.ahk und lädt diese, falls vorhanden. Dadurch kann MeinPräfix.ahk sowohl die Funktion MeinPräfix_MeineFunk als auch andere verwandte Funktionen enthalten, deren Namen mit MeinPräfix_ beginnen.

[AHK_L 42+]: Unterstützung für die lokale Bibliothek hinzugefügt, die vor der Benutzer- und Standardbibliothek durchsucht wird.

Nur ein direkter Funktionsaufruf wie MeineFunk() bewirkt, dass eine Bibliothek automatisch inkludiert wird. Wenn die Funktion nur dynamisch oder indirekt aufgerufen wird, z.B. via Timer oder GUI-Ereignis, muss die Bibliothek explizit in das Skript inkludiert werden. Zum Beispiel: #Include <MeineFunk>

Obwohl eine Bibliotheksdatei in der Regel nur eine einzelne Funktion mit demselben Namen wie die Datei enthält, kann sie auch private Funktionen und Subroutinen enthalten, die nur von ihr aufgerufen werden. Allerdings sollten solche Funktionen eindeutige Namen haben, da sie sich im globalen Namensraum befinden, d.h. sie können von überall im Skript aufgerufen werden.

Wenn eine Bibliotheksdatei #Include verwendet, ist das Arbeitsverzeichnis für #Include das Verzeichnis der Bibliotheksdatei. Dies kann verwendet werden, um eine Weiterleitung zu einer größeren Bibliotheksdatei zu schaffen, die diese Funktion und andere verwandte Funktionen enthält.

Der Skriptcompiler (ahk2exe) unterstützt ebenfalls Bibliotheksfunktionen. Der Compiler setzt aber voraus, dass eine Kopie von AutoHotkey.exe im Elternverzeichnis des Compiler-Verzeichnisses vorhanden ist (was normalerweise der Fall ist). Wenn der Compiler dort keine AutoHotkey.exe findet, funktioniert er zwar trotzdem, aber die Bibliotheksfunktionen werden nicht mehr automatisch inkludiert.

Funktionen, die aus einer Bibliothek inkludiert werden, sind genauso performant wie normale Funktionen, weil sie vor Beginn der Skriptausführung geladen werden.

Interne Funktionen

Alle optionalen Parameter am Ende der Parameterliste einer internen Funktion können komplett weggelassen werden. Zum Beispiel ist WinExist("Unbenannt - Editor") gültig, weil die anderen drei Parameter als leere Werte behandelt werden.

Eine interne Funktion gilt als überschrieben, wenn im Skript eine Funktion gleichen Namens definiert ist. Zum Beispiel könnte man anstelle der normalen WinExist()-Funktion eine selbstdefinierte Funktion verwenden. Allerdings kann danach die originale Funktion nicht mehr aufgerufen werden.

Externe Funktionen, die sich in DLL-Dateien befinden, können via DllCall() aufgerufen werden.

Um mehr über eine bestimmte interne Funktion zu erfahren, klicken Sie einfach auf den entsprechenden Namen.

Häufig verwendete Funktionen

Funktion Beschreibung
FileExist Prüft, ob eine Datei oder ein Ordner existiert, und gibt ihre/seine Attribute zurück.
GetKeyState Gibt 1 (true) oder 0 (false) zurück, je nachdem, ob die angegebene Tastatur-, Maus- oder Controllertaste unten oder oben ist.
InStr Sucht nach einem bestimmten Vorkommen einer Zeichenkette, beginnend von links oder rechts.
RegExMatch Prüft, ob ein Suchmuster (regulärer Ausdruck) in einer Zeichenkette vorkommt.
RegExReplace Ersetzt ein oder mehrere Vorkommen eines Suchmusters (regulären Ausdrucks) in einer Zeichenkette.
StrLen Ruft die Anzahl der Zeichen in einer Zeichenkette ab.
StrReplace Ersetzt eine bestimmte Teilzeichenkette mit einer neuen Zeichenkette.
StrSplit Teilt eine Zeichenkette mittels bestimmter Separatoren in mehrere Teilzeichenketten auf.
SubStr Ruft ein oder mehrere Zeichen von einer bestimmten Position in einer Zeichenkette ab.
WinActive Prüft, ob ein bestimmtes Fenster aktiv ist, und gibt dessen HWND-Nummer (eindeutige ID) zurück.
WinExist Prüft, ob ein bestimmtes Fenster existiert, und gibt die HWND-Nummer (eindeutige ID) des ersten gefundenen Fensters zurück.

Verschiedene Funktionen

Funktion Beschreibung
Asc Gibt einen numerischen Wert zurück, der das erste Byte oder die erste UTF-16-Codeeinheit einer bestimmten Zeichenkette repräsentiert.
Chr Gibt eine Zeichenkette zurück (üblicherweise ein einzelnes Zeichen), deren Zeichencode mit einer bestimmten Nummer übereinstimmt.
DllCall Ruft eine Funktion aus einer DLL-Datei auf, z.B. eine API-Funktion von Windows.
Exception Erstellt ein Objekt, das zum Auslösen einer benutzerdefinierten Ausnahme verwendet werden kann.
FileOpen Öffnet eine Datei, um bestimmte Inhalte aus ihr zu lesen und/oder in diese zu schreiben.
Format Formatiert eine beliebige Anzahl von Eingabewerten gemäß einer Formatzeichenkette.
Func Ruft die Referenz einer bestimmten Funktion ab.
GetKeyName/VK/SC Ruft den Namen/Text, virtuellen Tastencode oder Scancode einer Taste ab.
Hotstring Erstellt, modifiziert, aktiviert oder deaktiviert einen Hotstring, während das Skript läuft.
IL_XXX Funktionen zum Erstellen oder Löschen von ImageLists oder zum Einfügen von Symbolen/Bildern in ImageLists (für ListView- oder TreeView-Steuerelemente).
InputHook Erstellt ein Objekt, mit dem Tastatureingaben gesammelt oder abgefangen werden können.
IsByRef Gibt eine Zahl ungleich 0 zurück, wenn einem bestimmten ByRef-Parameter eine Variable übergeben wurde.
IsFunc Gibt eine Zahl ungleich 0 zurück, wenn eine bestimmte Funktion im Skript existiert.
IsLabel Gibt eine Zahl ungleich 0 zurück, wenn ein bestimmtes Label im Skript existiert.
IsObject Gibt eine Zahl ungleich 0 zurück, wenn ein bestimmter Wert ein Objekt ist.
IsSet Gibt eine Zahl ungleich 0 zurück, wenn einer bestimmten Variable ein Wert zugewiesen wurde.
LoadPicture Lädt ein Bild aus einer Datei und gibt ein Bitmap- oder Symbol-Handle zurück.
LV_XXX Funktion zum Hinzufügen, Einfügen, Modifizieren oder Löschen von ListView-Zeilen/Spalten oder zum Abrufen ihrer Daten.
NumGet Gibt die Binärzahl an einer bestimmten Adresse+Offset zurück.
NumPut Speichert eine Binärzahl an einer bestimmten Adresse+Offset.
ObjAddRef / ObjRelease Erhöht oder verringert die Referenzanzahl eines Objekts um 1.
ObjBindMethod Erstellt ein BoundFunc-Objekt, das eine Methode des angegebenen Objekts aufruft.
ObjGetBase Ruft das Basisobjekt eines Objekts ab.
ObjRawGet Ruft ein Schlüssel-Wert-Paar eines Objekts ab und umgeht dabei die Metafunktionen des Objekts.
ObjRawSet Speichert oder überschreibt ein Schlüssel-Wert-Paar in einem Objekt und umgeht dabei die Metafunktionen des Objekts.
ObjSetBase Setzt das Basisobjekt eines Objekts.
ObjXXX Funktionen, äquivalent zu den internen Methoden eines Objekts, wie z.B. ObjInsertAt. In der Regel ist es besser, die entsprechende Methode zu verwenden.
OnClipboardChange Registriert eine Funktion, die jedes Mal automatisch aufgerufen wird, wenn sich der Inhalt der Zwischenablage ändert.
OnError Registriert eine Funktion, die jedes Mal automatisch aufgerufen wird, wenn ein unbehandelter Fehler auftritt.
OnExit Registriert eine Funktion, die jedes Mal automatisch aufgerufen wird, wenn das Skript beendet wird.
OnMessage Registriert eine Funktion, die jedes Mal automatisch aufgerufen wird, wenn das Skript eine bestimmte Meldung empfängt.
Ord Gibt den Ordinalwert (numerischen Zeichencode) des ersten Zeichens in einer bestimmten Zeichenkette zurück.
SB_XXX Funktionen zum Einfügen von Text/Symbolen in die Leiste eines StatusBar-Steuerelements oder zum Aufteilen der Leiste in mehrere Segmente.
StrGet Kopiert eine Zeichenkette von einer Speicheradresse (optional mit Codepage-Umwandlung).
StrPut Kopiert eine Zeichenkette auf eine Speicheradresse (optional mit Codepage-Umwandlung).
RegisterCallback Erstellt eine Maschinencode-Adresse, die, wenn aufgerufen, den Aufruf an eine Funktion im Skript weiterleitet.
Trim / LTrim / RTrim Entfernt Zeichen vom Anfang und/oder Ende einer Zeichenkette.
TV_XXX Funktionen zum Hinzufügen, Modifizieren oder Löschen von TreeView-Elementen oder zum Abrufen ihrer Daten.
VarSetCapacity Erhöht die Speicherkapazität einer Variable oder gibt ihren Speicher frei.
VerCompare Vergleicht zwei Versionszeichenketten.

Mathematik

Funktion Beschreibung
Abs Gibt den Absolutwert einer bestimmten Zahl zurück.
Ceil Gibt eine bestimmte Zahl zurück, aufgerundet auf den nächsten Integer (ohne .00-Suffix).
Exp Gibt das Ergebnis von e (ca. 2.71828182845905) hoch N zurück.
Floor Gibt eine bestimmte Zahl zurück, abgerundet auf den nächsten Integer (ohne .00-Suffix).
Log Gibt den Logarithmus (Basis 10) einer bestimmten Zahl zurück.
Ln Gibt den Logarithmus (Basis e) einer bestimmten Zahl zurück.
Max / Min Gibt die höchste/niedrigste Zahl aus einer Reihe von Zahlen zurück.
Mod Modulo. Gibt den Rest aus einer Division zweier Zahlen zurück.
Round Gibt eine bestimmte Zahl zurück, gerundet auf N Dezimalstellen.
Sqrt Gibt die Quadratwurzel einer bestimmten Zahl zurück.
Sin / Cos / Tan Gibt den trigonometrischen Sinus/Kosinus/Tangens einer bestimmten Zahl zurück.
ASin / ACos / ATan Gibt den Arkussinus/Arkuskosinus/Arkustangens (die Zahl, deren Sinus/Kosinus/Tangens die angegebene Zahl ist) zurück (in Radiant).

COM

Funktion Beschreibung
ComObjActive Ruft ein registriertes COM-Objekt ab.
ComObjArray Erstellt ein SafeArray, das für COM verwendet werden kann.
ComObjConnect Verbindet die Ereignisquellen eines COM-Objekts mit Funktionen, die ein bestimmtes Präfix haben.
ComObjCreate Erstellt ein COM-Objekt.
ComObject Erstellt ein Objekt, das in typisierter Form als Parameter oder Rückgabewert übergeben werden kann.
ComObjEnwrap / ComObjUnwrap Wrappt/entwrappt ein COM-Objekt.
ComObjError Aktiviert oder deaktiviert COM-spezifische Fehlermeldungen.
ComObjFlags Ermittelt oder ändert Flags, die das Verhalten eines COM-Wrapper-Objekts kontrollieren.
ComObjGet Gibt eine Referenz zu einem Objekt zurück, das von einer COM-Komponente bereitgestellt wird.
ComObjMissing Erstellt ein Objekt für "fehlende Parameter" zur Übergabe an eine COM-Methode.
ComObjParameter Wrappt einen Wert und Typ zu einem Objekt, das einer COM-Methode als Parameter übergeben werden kann.
ComObjQuery Fragt ein COM-Objekt nach einem Interface oder Service ab.
ComObjType Ruft Typinformationen eines COM-Objekts ab.
ComObjValue Ruft den Wert oder Pointer ab, der in einem COM-Wrapper-Objekt hinterlegt ist.

Sonstige Funktionen

Befehlsfunktionen von Polyethene: Bietet eine aufrufbare Funktion für jeden AutoHotkey-Befehl, der eine Ausgabevariable hat. Diese Bibliothek kann via #Include in ein beliebiges Skript inkludiert werden.