Direkt geschriebene Zuweisungen wurden entfernt: Var = Wert
Alle Legacy-If-Anweisungen wurden entfernt, so dass nur noch if Ausdruck
übrig bleibt, das nie Klammern erfordert (aber erlaubt, wie bei jedem Ausdruck).
Die "Befehlssyntax" wurde entfernt. Es gibt keine "Befehle" mehr, sondern nur noch Funktionsaufrufanweisungen - das sind nichts anderes als Funktions- oder Methodenaufrufe ohne runde Klammern. Das bedeutet:
WinMove(, y)
gleich WinMove , y
(x wurde weggelassen). Ein Leer- oder Tabulatorzeichen ist erforderlich. Aus Konsistenzgründen folgen auch Direktiven der neuen Konvention (zwischen dem Direktivennamen und dem ersten Parameter darf kein Komma stehen).Var.Eigenschaft.Methode "Zeichenkette"
.Die Übersetzung von v1-Befehlen in Funktionen verlief in der Regel wie folgt (einige Funktionen wurden jedoch geändert, wie weiter unten dokumentiert):
Alle Kontrollanweisungen akzeptieren auch Ausdrücke, außer wo unten angegeben.
Alle Kontrollanweisungen, die Parameter akzeptieren (außer Zwei-Wort-Schleifenanweisungen), unterstützen runde Klammern um ihre Parameterliste, ohne Leerzeichen zwischen dem Namen und der Klammer. Zum Beispiel return(var)
. Dies sind jedoch keine Funktionen, z.B. ist x := return(y)
ungültig. If und While unterstützen dies bereits.
Auf Loop (außer Loop Wiederholungen) folgt nun ein sekundäres Schlüsselwort (Files, Parse, Read oder Reg), das weder in Anführungszeichen gesetzt noch in einer Variable enthalten sein darf. Derzeit kann hinter dem Schlüsselwort ein Komma stehen, was aber nicht erforderlich ist, da dies kein Parameter ist. OTB wird bei allen Varianten unterstützt.
Goto, Break und Continue benötigen einen anführungszeichenlosen Labelnamen, äquivalent zu v1 (Goto Label
springt zu Label:
). Um dynamisch zu einem Label zu springen, verwenden Sie runde Klammern direkt hinter dem Namen: Goto(Ausdruck)
. Dies ist jedoch keine Funktion und kann nicht innerhalb eines Ausdrucks verwendet werden. Es können runde Klammern bei Break oder Continue verwendet werden, aber dann muss der Parameter eine direkt geschriebene Zahl oder eine in Anführungszeichen gesetzte Zeichenkette sein.
Gosub wurde entfernt, und Labels können nicht mehr mit Funktionen wie SetTimer und Hotkey verwendet werden.
{
ein entsprechendes }
haben muss. Die Grenzen einer Funktion sollten auch leichter zu erkennen sein als die einer Label-Subroutine.Hotkeys und nicht-automatisch-ersetzende Hotstrings sind keine Labels mehr, sondern definieren (automatisch) eine Funktion. Verwenden Sie geschweifte Klammern bei mehrzeiligen Hotkeys, um den Körper des Hotkeys zu umschließen, anstatt ihn mit return
zu beenden (was durch die geschweifte Endklammer impliziert wird). Um einen Hotkey explizit aufrufen zu lassen, geben Sie FunkName(ThisHotkey)
zwischen ::
und {
an - dies ist auch in v1.1.20+ möglich, aber es gibt jetzt einen Parameter. Wenn die Funktionsdefinition nicht explizit ist, heißt der Parameter ThisHotkey.
Hinweis: Hotkey-Funktionen sind standardmäßig Assume-Local-Funktionen und können daher globalen Variablen nichts ohne Deklaration zuweisen.
Funktions- und Variablennamen befinden sich nun in einem gemeinsamen Namensraum.
MeineFunk
anstelle von Func("MeineFunk")
.MeineFunk
anstelle von "MeineFunk"
, um die Funktion an eine interne Funktion wie SetTimer oder Hotkey zu übergeben. Die Übergabe eines Namens (Zeichenkette) wird nicht mehr unterstützt.meineVar()
anstelle von %meineVar%()
, um eine Funktion per Wert aufzurufen.%meineVar%()
führt nun eine Doppeldereferenzierung (double-deref) durch und ruft dann das Ergebnis auf, äquivalent zu f := %meineVar%, f()
. Vermeiden Sie nach Möglichkeit die Adressierung von Funktionen über ihren Namen (Zeichenkette); verwenden Sie stattdessen Referenzen.Die Namen dürfen weder mit einer Ziffer beginnen noch die folgenden früher zulässigen Zeichen enthalten: @ # $
. Nur Buchstaben, Zahlen, Unterstriche und ASCII-fremde Zeichen sind erlaubt.
Reservierte Wörter: Deklarationsschlüsselwörter und Namen von Kontrollanweisungen dürfen nicht als Variablen-, Funktions- oder Klassennamen verwendet werden. Dazu gehören local
, global
, static
, if
, else
, loop
, for
, while
, until
, break
, continue
, goto
, return
, switch
, case
, try
, catch
, finally
und throw
. Dies dient in erster Linie der Fehlererkennung, z.B. if (ex) break
.
Reservierte Wörter: as
, and
, contains
, false
, in
, is
, IsSet
, not
, or
, super
, true
, unset
. Diese Wörter sind für zukünftige oder andere spezifische Zwecke reserviert und dürfen nicht als Variablen- oder Funktionsnamen verwendet werden. Dies dient in erster Linie der Konsistenz: In v1 war and := 1
in einer eigenen Zeile erlaubt, aber (and := 1)
hätte nicht funktioniert.
Die oben aufgelisteten Wörter können zur Benennung von Eigenschaften oder Fenstergruppen verwendet werden. Üblicherweise wird den Eigenschaftsnamen ein .
vorangestellt, um zu verhindern, dass das Wort als Operator interpretiert wird. Schlüsselwörter hingegen werden innerhalb eines Ausdrucks nie als Variablen- oder Funktionsnamen interpretiert. Zum Beispiel ist not(x)
äquivalent zu not (x)
oder (not x)
.
Einige Klassen sind vordefiniert, wodurch diese globalen Variablennamen auf die gleiche Weise reserviert sind wie bei einer benutzerdefinierten Klasse. (Die meisten Probleme, die sich daraus ergeben, werden jedoch durch die unten beschriebenen Änderungen am Gültigkeitsbereich entschärft.) Eine Liste der Klassen finden Sie unter Interne Klassen.
Superglobale Variablen wurden entfernt (außer interne Variablen, die nicht ganz dasselbe sind, da sie weder neu deklariert noch "überschrieben" werden können).
Wenn innerhalb einer Assume-Local-Funktion ein bestimmter Name nicht in einer Deklaration oder als Ziel einer nicht-dynamischen Zuweisung oder des Referenzoperators (&) verwendet wird, kann er in eine bestehende globale Variable aufgelöst werden.
Mit anderen Worten:
global
) haben, können globale Variablen nicht direkt ändern (dadurch wird eine Quelle für unbeabsichtigte Seiteneffekte eliminiert).class
) wird das Verhalten einer bestehenden Funktion viel weniger beeinflussen, da Klassen nicht superglobal sind.global
ist derzeit redundant, wenn es im globalen Bereich verwendet wird, kann aber zwecks Übersicht weiterhin angegeben werden. Variablen, die auf diese Weise deklariert werden, sind nun viel weniger anfällig für Konflikte mit lokalen Variablen (z.B. beim Kombinieren von Skripten, egal ob manuell oder mit #Include), da sie nicht superglobal sind. Andererseits geht etwas Komfort verloren.Der Force-Local-Modus wurde entfernt.
Lokale statische Variablen werden initialisiert, wenn und sobald sie von der Ausführung erreicht werden, nicht mehr in linearer Reihenfolge vor Beginn des automatischen Ausführungsbereichs. Jeder Initialisierer, der zum zweiten Mal erreicht wird, hat keinen Effekt mehr. Mehrere Deklarationen sind erlaubt und können für dieselbe Variable zu unterschiedlichen Zeitpunkten ausgeführt werden. Dies hat mehrere Vorteile:
if IsSet()
benötigt wird.static x += 1
zulässig. (Diese Änderung reduzierte die Codegröße nur geringfügig, da dies bereits bei local
und global
erlaubt war.)Hinweis: static init := MeineFunk()
kann nicht mehr verwendet werden, um MeineFunk automatisch auszuführen. Da jedoch Label-und-Return-basierte Subroutinen nun vollständig vermieden werden können, kann sich der automatische Ausführungsbereich über das gesamte Skript erstrecken.
Das Deklarieren einer Variable mit local
macht die Funktion nicht mehr zu einer Assume-Global-Funktion.
Doppeldereferenzen (double-derefs) sind nun konsistenter mit Variablen, die beim Laden des Skripts aufgelöst werden, und können keine neuen Variablen mehr erzeugen. Dadurch werden einige Inkonsistenzen und häufige Anlässe zu Verwirrung vermieden.
Doppeldereferenzen (double-derefs), die aus irgendeinem Grund fehlschlagen, lösen jetzt einen Fehler aus. Früher wurde bei ungültigen Namen stillschweigend eine leere Zeichenkette erzeugt, während in anderen Fällen eine leere Variable erstellt und zurückgegeben wurde.
Direkt geschriebene Zeichenketten können in "doppelten"
oder 'einfachen'
Anführungszeichen gesetzt werden, müssen aber mit demselben Zeichen beginnen und enden. Direkt geschriebene Anführungszeichen müssen mit einem Escapezeichen versehen werden - `"
oder `'
- oder mit dem gegenteiligen Anführungszeichen ersetzt werden: '"42" ist die Antwort'
. Zwei aufeinanderfolgende Anführungszeichen haben keine besondere Bedeutung und lösen einen Fehler aus, da eine Auto-Verkettung ein Leerzeichen benötigt.
Die Operatoren &&
, ||
, and
und or
geben, ähnlich wie JavaScript und Lua, den gewinnenden Wert zurück. Zum Beispiel bewirkt "" or "Standard"
die Rückgabe von "Standard" statt 1. Skripte, die einen reinen booleschen Wert (0 oder 1) benötigen, können so etwas wie !!(x or y)
oder (x or y) ? 1 : 0
verwenden.
Auto-Verkettungen benötigen nun mindestens ein Leer- oder Tabulatorzeichen (in der v1-Dokumentation hieß es "sollte" ein Leerzeichen sein).
Das Ergebnis eines Mehrfachanweisungsausdrucks wie x(), y()
ist der letzte (ganz rechts befindliche) Teilausdruck, anstatt der erste (ganz links). In v1 und v2 werden Teilausdrücke von links nach rechts ausgewertet.
Gleichheitszeichen nach einem Komma sind nicht länger Zuweisungen: y=z
in x:=y, y=z
wäre keine Zuweisung, sondern ein unwirksamer Vergleich.
:=
, +=
, -=
, *=
, /=
, ++
und --
verhalten sich konsistent, egal ob sie allein oder in Kombination mit anderen Operatoren verwendet werden, wie z.B. bei x := y, y += 2
. Früher gab es Unterschiede im Verhalten, wenn ein Fehler im Ausdruck auftrat oder ein leerer Wert in einer mathematischen Operation verwendet wurde.
!=
ist nun wie =
immer nicht-Groß-/Kleinschreibung-sensitiv, während !==
als Gegenstück zu ==
hinzugefügt wurde.
<>
wurde entfernt.
//
löst nun eine Ausnahme aus, wenn einer der Eingabewerte eine Floating-Point-Zahl ist. Früher waren die Ergebnisse zwischen negativen Floating-Point-Zahlen und negativen Integern inkonsistent.
|
, ^
, &
, <<
und >>
lösen nun eine Ausnahme aus, wenn einer ihrer Eingabewerte eine Floating-Point-Zahl ist, anstatt das Ergebnis auf einen Integer zu kürzen.
Die wissenschaftliche Schreibweise kann ohne Dezimalpunkt verwendet werden (erzeugt aber immer eine Floating-Point-Zahl). Die wissenschaftliche Schreibweise wird auch unterstützt, wenn numerische Zeichenketten in Integer umgewandelt werden (z.B. wird "1e3"
als 1000 statt 1 interpretiert).
Funktionsaufrufe können jetzt praktisch mit jedem Teilausdruck angegeben werden, welche Funktion aufgerufen werden soll, solange vor der runden Startklammer der Parameterliste kein Leer- oder Tabulatorzeichen steht. Zum Beispiel würde MeineFunk()
den Wert von MeineFunk aufrufen, egal ob es der tatsächliche Name einer Funktion oder eine Variable mit einem Funktionsobjekt ist, und (a?b:c)()
würde je nach a entweder b oder c aufrufen. Beachten Sie, dass x.y()
immer noch ein Methodenaufruf ist, ähnlich zu (x.y)(x)
, aber a[i]()
ist jetzt äquivalent zu (a[i])()
.
Doppeldereferenzen (double-derefs) erlauben nun fast jeden Ausdruck (nicht nur Variablen) als Quelle für den Variablennamen. Zum Beispiel sind DoNotUseArray%n+1%
und %(%triple%)%
gültig. Die Syntax für Doppeldereferenzierung (double-deref) wird nun auch für die Dereferenzierung von VarRefs verwendet, z.B. ref := &var, value := %ref%
.
Die Ausdrücke funkName[""]()
und funkName.()
rufen nicht länger eine Funktion via Name auf. Das Weglassen des Methodennamens wie in .()
verursacht nun eine Ladezeitfehlermeldung. Funktionen sollten per Referenz aufgerufen oder adressiert werden, nicht per Name.
var :=
löst einen Ladezeitfehler aus. In v1 war dies äquivalent zu var := ""
, scheiterte aber stillschweigend in Kombination mit einem anderen Ausdruck, z.B. x :=, y :=
.
Direkt geschriebene Zeichenketten gefolgt von einem mehrdeutigen unären/binären Operator lösen einen Ladezeitfehler aus. Wenn man z.B. mit "Neuer Zähler:" ++Zähler
versuchen will, Zähler um 1 zu erhöhen und anzuzeigen, wird eine Fehlermeldung angezeigt, da es technisch gesehen eine ungültige Addition und ein unäres Plus ist.
Wort ++
und Wort --
sind keine Ausdrücke mehr, da Wort
eine benutzerdefinierte Funktion sein kann (und nach ++/-- kann ein Ausdruck folgen, der eine Variablenreferenz erzeugt). Um einen alleinstehenden Post-Inkrement- oder Post-Dekrement-Ausdruck zu schreiben, muss entweder das Leerzeichen zwischen der Variable und dem Operator weggelassen oder die Variable oder der Ausdruck in runden Klammern gesetzt werden.
Wort ? x : y
ist immer noch ein ternärer Ausdruck, aber bei komplexeren Fällen, die mit einem Wort beginnen, z.B. Wort1 Wort2 ? x : y
, wird Wort1 immer als Funktionsaufruf interpretiert (auch wenn eine solche Funktion nicht existiert). Um einen alleinstehenden ternären Ausdruck mit einer komplexen Bedingung zu schreiben, umschließen Sie die Bedingung mit runden Klammern.
Mit dem neuen is
-Operator wie in x is y
kann geprüft werden, ob der Wert x eine Instanz der Klasse y ist, wobei y ein Objekt mit einer Prototype-Eigenschaft (also eine Klasse) sein muss. Dies schließt auch primitive Werte wie in x is Integer
ein (was eine reine Typprüfung ist, während IsInteger(x)
auf eine mögliche Umwandlung prüft).
Die Schlüsselwörter contains
und in
sind für zukünftige Zwecke reserviert.
&var
(Adressoperator) wurde durch StrPtr(var)
und ObjPtr(obj)
ersetzt, um die Intention zu verdeutlichen und die Fehlerprüfung zu verbessern. In v1 gab der Adressoperator die Adresse des internen Zeichenkettenpuffers von var zurück, auch dann, wenn dieser eine Zahl (aber kein Objekt) enthielt. Der Operator wurde auch verwendet, um die Adresse eines Objekts abzurufen. Das Abrufen einer Adresse falschen Typs kann schlimme Folgen haben.
&var
ist nun der Referenzoperator, der für alle ByRef- und AusgabeVar-Parameter verwendet wird, um die Übersichtlichkeit und Flexibilität zu verbessern (und weitere Sprachänderungen zu ermöglichen). Weitere Informationen finden Sie unter Variablenreferenzen (VarRef).
Die Länge der Zeichenkette wird nun während der Ausdrucksauswertung im Cache zwischengespeichert. Dies verbessert die Performanz und erlaubt binäre Nullen in Zeichenketten. Genauer gesagt:
==
und !==
) können Binärdaten verglichen werden. Die anderen Vergleichsoperatoren können nur bis zur ersten binären Null "sehen".Die meisten Funktionen erwarten immer noch nullterminierte Zeichenketten, d.h. sie können nur bis zur ersten binären Null "sehen". Zum Beispiel würde MsgBox nur den Teil der Zeichenkette vor der ersten binären Null anzeigen.
Der *
-Operator (Dereferenz) wurde entfernt. Verwenden Sie stattdessen NumGet.
Der ~
-Operator (bitweises NICHT) behandelt seinen Eingabewert nun immer als vorzeichenfähigen 64-Bit-Integer, d.h. er behandelt Werte zwischen 0 und 4294967295 nicht mehr als vorzeichenlose 32-Bit-Integer.
>>>
und >>>=
für logische bitweise Verschiebung nach rechts wurden hinzugefügt.
Fat-Arrow-Funktionen wurden hinzugefügt. Der Ausdruck Fn(Parameter) => Ausdruck
definiert eine Funktion namens Fn (was weggelassen werden kann) und gibt ein Func-Objekt oder Closure-Objekt zurück. Bei Aufruf wertet die Funktion Ausdruck aus und gibt das Ergebnis zurück. Wenn dies in einer anderen Funktion verwendet wird, kann Ausdruck auf die Variablen der äußeren Funktion verweisen (was auch mit einer normalen Funktionsdefinition erreicht werden kann).
Die Fat-Arrow-Syntax kann auch verwendet werden, um Methoden und Eigenschafts-Getter/Setter zu definieren (in diesem Fall ist die Methoden-/Eigenschaftsdefinition selbst kein Ausdruck, sondern ihr Körper gibt einfach einen Ausdruck zurück).
Direkt geschriebene Zahlen werden nun auf der linken Seite des Objektelementzugriffs (Punkt) vollständig unterstützt. Zum Beispiel ist 0.1
eine Zahl, aber 0.min
und 0.1.min
greifen auf die min-Eigenschaft zu, die von einem Basisobjekt behandelt werden kann (siehe Primitive Werte). 1..2
oder 1.0.2
ist die Zahl 1.0, gefolgt von der Eigenschaft 2. Dies kann z.B. für Maßeinheiten, direkt geschriebene Versionsnummern oder Zahlenbereiche verwendet werden.
x**y
: Wenn x und y Integer sind und y positiv ist, liefert der Potenzoperator nun korrekte Ergebnisse für alle Eingabewerte, sofern im gültigen Bereich, während früher durch die interne Floating-Point-Berechnung eine gewisse Genauigkeit verloren ging. Das Verhalten bei Überlauf ist undefiniert.
Siehe auch: Objekte
Der Zugriff auf Eigenschaften via .
und der Zugriff auf Daten (Array- oder Map-Elemente) via []
werden nun getrennt voneinander behandelt. Zum Beispiel kann dictionary["Count"]
die Definition von "Count" zurückgeben, während dictionary.Count
die Anzahl der darin enthaltenen Wörter zurückgibt. Benutzerdefinierte Objekte können dies durch Definieren einer __Item-Eigenschaft nutzen.
Wenn der Name einer Eigenschaft oder Methode nicht im Voraus bekannt ist, können (und müssen) Prozentzeichen verwendet werden, um auf sie zuzugreifen. Zum Beispiel ist obj.%varname%()
das v2-Äquivalent von obj[varname]()
. Die Verwendung von []
ist für Daten (z.B. Array-Elemente) reserviert.
Die direkte Schreibweise zum Konstruieren eines Ad-hoc-Objekts ist nach wie vor {Name: Wert}
, aber da reine Objekte jetzt nur noch "Eigenschaften" und keine "Array-Elemente" mehr haben, wurden die Regeln leicht geändert, um konsistent mit der Art und Weise zu sein, wie alle anderen Zugriffe auf Eigenschaften erfolgen:
o := {a: b}
verwendet wie zuvor den Namen "a".o := {%a%: b}
verwendet den Eigenschaftsnamen in a, anstatt diesen als Variablennamen zu nehmen, eine Doppeldereferenzierung (double-deref) durchzuführen und den Inhalt der resultierenden Variable zu verwenden. Mit anderen Worten, es hat denselben Effekt wie o := {}, o.%a% := b
.:
ist unzulässig. Zum Beispiel {(a): b}
oder {ein Fehler: 1}
.Die Verwendung des Wortes "base" in base.Methode()
wurde mit super ersetzt (super.Methode()
), um die beiden Konzepte besser zu unterscheiden:
super.
oder super[
ruft die Superklassenversion einer Methode/Eigenschaft auf, wobei "Superklasse" die Basis des Prototypobjekts ist, das ursprünglich zur Definition der aktuellen Funktion gehörte.super
ist ein reserviertes Wort; der Versuch, es ohne das Suffix .
oder [
oder (
oder außerhalb einer Klasse zu verwenden, führt zu einem Ladezeitfehler.base
ist eine vordefinierte Eigenschaft, die das unmittelbare Basisobjekt des Objekts abruft oder setzt (wie ObjGetBase/ObjSetBase). Es ist nur ein normaler, nicht reservierter Eigenschaftsname.super.x
löst einen Fehler aus, wenn die Superklasse keine Definition von x hat, während base.x
früher ignoriert wurde (auch wenn es eine Zuweisung war).Der Aufruf eines benutzerdefinierten Objekts ohne explizite Angabe eines Methodennamens bewirkt nun den Aufruf der "Call"-Methode anstelle der ""-Methode. Zum Beispiel bewirkte %Fn%()
früher den Aufruf von Fn.()
, während der v2-Ausdruck Fn()
den Aufruf von Fn.Call()
bewirkt. Func-Objekte implementieren nicht mehr die namenlose Methode. Es ist nicht mehr zulässig, den Methodennamen in einem Methodenaufruf wegzulassen, aber Fn.%""%()
funktioniert anstelle von Fn.()
.
this.Method()
ruft Fn.Call(this)
(wobei Fn das Funktionsobjekt ist, das die Methode implementiert) statt Fn[this]()
auf (was in v1 zu einem Aufruf von Fn.__Call(this)
führen würde, es sei denn, Fn[this]
enthält eine Funktion). Funktionsobjekte sollten eine Call-Methode implementieren, nicht __Call, das nur für explizite Methodenaufrufe vorgesehen ist.
Klassenname()
(ehemals new Klassenname()
) scheitert nun bei der Erstellung des Objekts, wenn die __New-Methode definiert ist, aber nicht aufgerufen werden konnte (z.B. weil die Parameteranzahl falsch ist), oder wenn Parameter übergeben wurden, aber __New nicht definiert ist.
Objekte, die innerhalb eines Ausdrucks erstellt oder von einer Funktion zurückgegeben werden, werden nun zurückgehalten, bis die Auswertung des Ausdrucks abgeschlossen ist, und dann freigegeben. Dies verbessert die Performanz geringfügig und ermöglicht die Verwendung temporärer Objekte für die Speicherverwaltung innerhalb eines Ausdrucks, ohne zu befürchten, dass die Objekte vorzeitig freigegeben werden.
Objekte können Zeichenkettenwerte (aber keine Schlüssel) mit binären Nullen enthalten. Beim Klonen eines Objekts werden Binärdaten in Zeichenketten beibehalten, bis zur gespeicherten Länge der Zeichenkette (nicht ihre Kapazität). Früher wurden Daten über die Länge des Wertes hinaus geschrieben, wenn es um Binärdaten oder Strukturen ging; jetzt sollte stattdessen ein Buffer-Objekt verwendet werden.
Zuweisungsausdrücke wie x.y := z
liefern nun immer den Wert von z, egal wie x.y implementiert wurde. Der Rückgabewert eines Eigenschafts-Setters wird nun ignoriert. Früher:
c := GuiObj.BackColor := "red"
, das c auf 0xFF0000 gesetzt hat), und wieder andere gaben einen falschen Wert zurück.x.y(z) := v
ist nun ein Syntaxfehler. Früher war dies äquivalent zu x.y[z] := v
. Grundsätzlich sind x.y(z)
(Methodenaufruf) und x.y[z]
(parametrisierte Eigenschaft) zwei verschiedene Operationen, werden aber als äquivalent betrachtet, wenn x ein COM-Objekt ist (aufgrund von Einschränkungen der COM-Schnittstelle).
Die Verkettung eines Objekts mit einem anderen Wert oder dessen Übergabe an Loop wird derzeit als Fehler behandelt, während das Objekt früher als leere Zeichenkette behandelt wurde. Dies kann durch impliziten Aufruf von .ToString()
geändert werden. Verwenden Sie String(x)
, um einen Wert in eine Zeichenkette umzuwandeln; dies ruft .ToString()
auf, wenn x ein Objekt ist.
Beim Aufruf eines Objekts via IDispatch (die COM-Schnittstelle) führen unbehandelte Ausnahmen, die nicht an den Aufrufer zurückgegeben werden können, zu einem Fehlerdialogfenster. (Der Aufrufer kann nach Belieben ein zusätzliches Fehlerdialogfenster ohne spezifische Details anzeigen.) Dies gilt auch für den Aufruf von Ereignishandlern durch Verwendung von ComObjConnect.
Funktionen können nicht mehr dynamisch mit mehr Parametern als formal möglich aufgerufen werden.
Variadische Funktionen sind von der obigen Einschränkung nicht betroffen, erstellen aber normalerweise bei jedem Aufruf ein Array, das die überschüssigen Parameter enthält. Wenn dieses Array nicht benötigt wird, kann der Parametername nun weggelassen werden, um seine Erstellung zu verhindern:
AkzeptiertEinOderMehrArgs(erster, *) { ... }
Dies kann für Rückruffunktionen verwendet werden, wo die zusätzlichen Parameter nicht benötigt werden.
Variadische Funktionsaufrufe erlauben nun die Verwendung eines enumerierbaren Objekts in Situationen, wo früher ein Standardobjekt mit sequentiellen numerischen Schlüsseln erforderlich war. Wenn der Enumerator mehr als einen Wert pro Wiederholung zurückgibt, wird nur der erste Wert verwendet. Zum Beispiel erstellt Array(mymap*)
ein Array, das die Schlüssel von mymap enthält.
Variadische Funktionsaufrufe hatten früher nur eine halbherzige Unterstützung für benannte Parameter. Dies wurde deaktiviert, um ein mögliches Hindernis für die ordnungsgemäße Implementierung von benannten Parametern zu beseitigen.
Benutzerdefinierte Funktionen können das neue Schlüsselwort unset
als Standardwert eines Parameters verwenden, um den Parameter "ungesetzt" zu machen, wenn kein Wert bereitgestellt wurde. Die Funktion kann dann IsSet() verwenden, um festzustellen, ob ein Wert bereitgestellt wurde. unset
ist derzeit in keinem anderen Kontext erlaubt.
Skripte werden nicht mehr automatisch aus den Funktionsbibliotheksordnern (Lib) inkludiert, wenn ein Funktionsaufruf ohne Definition vorhanden ist, wegen der erhöhten Komplexität und der Gefahr von Unfällen (jetzt, da das MeineFunk in MeineFunk()
eine beliebige Variable sein kann). #Include <BiblName>
funktioniert wie früher. Möglicherweise wird dies in einer zukünftigen Version durch Modulunterstützung ersetzt.
Variadische interne Funktionen haben jetzt einen MaxParams-Wert äquivalent zu MinParams, anstatt einer willkürlichen Zahl (wie 255 oder 10000). Verwenden Sie die IsVariadic-Eigenschaft, um festzustellen, ob es keine Obergrenze gibt.
ByRef-Parameter werden jetzt nicht mehr mit ByRef param
, sondern mit ¶m
deklariert, mit einigen Unterschieden in der Verwendung.
ByRef-Parameter nehmen nicht mehr implizit eine Referenz, die auf die Variable des Aufrufers verweist. Stattdessen muss der Aufrufer explizit eine Referenz mit dem Referenzoperator (&var
) übergeben. Dies erlaubt mehr Flexibilität, z.B. Referenzen woanders zu speichern, sie mit einer variadischen Funktion zu akzeptieren und sie mit einem variadischen Aufruf weiterzugeben.
Wenn ein Parameter als ByRef markiert ist, löst jeder Versuch, explizit einen Nicht-VarRef-Wert zu übergeben, einen Fehler aus. Andernfalls kann die Funktion erstens mit param is VarRef
prüfen, ob eine Referenz vorliegt, zweitens mit IsSetRef(param)
prüfen, ob die Zielvariable einen Wert hat, und drittens diese mit %param%
explizit dereferenzieren.
ByRef-Parameter können nun eine Referenz erhalten, die auf eine lokale Variable aus einer vorherigen Instanz der gleichen Funktion verweist, wenn diese rekursiv aufgerufen wird.
Eine Funktion kann innerhalb einer anderen Funktion definiert werden. Eine verschachtelte Funktion kann automatisch nicht-statische lokale Variablen von der äußeren Funktion "abfangen" (unter den richtigen Bedingungen), wodurch diese nach Abschluss der äußeren Funktion verwendet werden können.
Der neue Fat-Arrow-Operator =>
kann auch verwendet werden, um verschachtelte Funktionen zu erstellen.
Alle Details finden Sie unter Verschachtelte Funktionen.
Bei der Initialisierung einer deklarierten Variable oder eines optionalen Parameters muss :=
statt =
verwendet werden.
return %var%
bewirkt nun eine Doppeldereferenzierung (double-deref); früher war es äquivalent zu return var
.
#Include ist standardmäßig relativ zum Verzeichnis, das die aktuelle Datei enthält. Der Parameter dieser Direktive kann nun optional in Anführungszeichen gesetzt werden.
Der Parameter von #ErrorStdOut kann nun optional in Anführungszeichen gesetzt werden.
Labelnamen dürfen nun nur noch aus Buchstaben, Ziffern, Unterstrichen und ASCII-fremden Zeichen bestehen (dasselbe gilt für Variablen, Funktionen und so weiter).
Labels innerhalb einer Funktion werden lokal behandelt, d.h. sie sind nur innerhalb dieser Funktion "sichtbar" und stehen nicht in Konflikt mit anderen Labels außerhalb der Funktion. Es ist nicht möglich, lokale Labels extern aufzurufen (auch nicht via interne Funktionen). Stattdessen können verschachtelte Funktionen verwendet werden, die die volle Nutzung lokaler Variablen erlauben.
for k, v in obj
:
Ein Komma mit einem Escapezeichen zu versehen, ist nicht mehr wichtig. Wenn `,
früher in einem Ausdruck innerhalb eines Befehlsparameters ohne runde Klammern verwendet wurde, wurde das Komma als Mehrfachanweisungsoperator interpretiert, nicht als Parametertrennung. Dies funktionierte nur bei Befehlen, nicht bei Funktionen oder Variablendeklarationen.
Die Escapesequenz `s
ist jetzt überall erlaubt, wo `t
unterstützt wird. Früher war sie nur bei #IfWin und (Join erlaubt.
*/
kann nun am Ende einer Zeile stehen, um einen mehrzeiligen Kommentar zu schließen, wodurch eine häufige Verwechslung bezüglich der Funktionsweise von /* */
in anderen Sprachen behoben wird. Wegen der Gefahr von Mehrdeutigkeit (z.B. bei einem Hotstring, der auf */
endet) wird ein */
, dem kein /*
vorangestellt ist, nicht mehr ignoriert (eine Änderung in AHK_L Revision 54 wurde rückgängig gemacht).
Integerkonstanten und numerische Zeichenketten außerhalb des unterstützten Bereichs (von vorzeichenbehafteten 64-Bit-Integern) werden nun überlaufen/umgekehrt, anstatt auf den Minimal-/Maximalwert begrenzt zu werden. Dies ist konsistent mit mathematischen Operatoren, daher ist 9223372036854775807+1 == 9223372036854775808
(aber beide erzeugen -9223372036854775808). Dies ermöglicht bitweise Operationen mit 64-Bit-Werten.
Bei numerischen Zeichenketten gibt es weniger Fälle, wo andere Leerraumzeichen als Leer- und Tabulatorzeichen der Zahl vorangestellt werden dürfen. In der Regel (sowohl in v1 als auch in v2) sind nur Leer- und Tabulatorzeichen erlaubt, aber in einigen Fällen werden andere Leerraumzeichen zugunsten von C-Laufzeitbibliothek-Konventionen toleriert.
Else kann nun zusammen mit Schleifen beliebigen Typs und Catch verwendet werden. Bei Schleifen wird es ausgeführt, wenn die Schleife null Wiederholungen hatte. Bei Catch wird es ausgeführt, wenn innerhalb von Try keine Ausnahme ausgelöst wird (und nicht ausgeführt, wenn ein Fehler oder ein Wert ausgelöst wird, auch wenn es kein Catch gibt, das der Klasse des Wertes entspricht). Folglich kann die Interpretation von Else abweichen, wenn es ohne geschweifte Klammern verwendet wird. Zum Beispiel:
if Bedingung { while Bedingung ; Pro Wiederholung auszuführende Anweisung } ; Diese Klammern sind jetzt erforderlich, sonst assoziiert Else mit While else ; Auszuführende Anweisung, wenn Bedingung False ist
Smartes LTrim: Standardmäßig werden alle Leer- oder Tabulatorzeichen am Anfang der ersten Zeile unter den Fortsetzungsbereichsoptionen gezählt und dann diese Anzahl von Leer- oder Tabulatorzeichen aus jeder nachfolgenden Zeile entfernt. Wenn die erste Zeile eine Mischung aus Leer- und Tabulatorzeichen enthält, wird nur der erste Zeichentyp als Einrückung behandelt. Wenn eine Zeile weniger eingerückt ist als die erste Zeile oder mit den falschen Zeichen eingerückt ist, bleiben alle Leerraumzeichen am Anfang dieser Zeile erhalten.
Anführungszeichen werden automatisch mit einem Escapezeichen versehen (also als direkt geschriebene Zeichen interpretiert), wenn der Fortsetzungsbereich innerhalb einer in Anführungszeichen gesetzten Zeichenkette beginnt. Dadurch wird verhindert, dass Anführungszeichen in mehrzeiligen Zeichenketten mit einem Escapezeichen versehen werden müssen (wenn das beginnende und endende Anführungszeichen außerhalb des Fortsetzungsbereichs liegen), während mehrzeilige Ausdrücke immer noch in Anführungszeichen gesetzte Zeichenketten enthalten können.
Wenn die Zeile über dem Fortsetzungsbereich mit einem Namenszeichen endet und der Bereich nicht innerhalb eines Anführungszeichens beginnt, wird automatisch ein einzelnes Leerzeichen eingefügt, um den Namen vom Inhalt des Fortsetzungsbereichs zu trennen. Dadurch kann ein Fortsetzungsbereich für einen mehrzeiligen Ausdruck verwendet werden, dem ein return
, Funktionsaufrufanweisungen usw. vorangestellt sind. Es stellt auch sicher, dass Variablennamen nicht mit anderen Tokens (oder Namen) verbunden werden, was zu ungültigen Ausdrücken führt.
Zeilenumbruchzeichen (`n
) werden in Ausdrücken als Leerzeichen behandelt. Dies ermöglicht es, Ausdrücke unter Verwendung eines Fortsetzungsbereichs mit Standardoptionen (d.h. Join
weglassen) mehrzeilig zu machen.
Die Optionen ,
und %
wurden entfernt, da diese Zeichen nicht mehr mit einem Escapezeichen versehen werden müssen.
Wenn (
oder )
in den Optionen eines potenziellen Fortsetzungsbereichs erscheint (außer als Teil der Join
-Option), wird die gesamte Zeile nicht als Beginn eines Fortsetzungsbereichs interpretiert. Mit anderen Worten, Zeilen wie (x.y)()
und (x=y) && z()
werden als Ausdrücke interpretiert. Ein mehrzeiliger Ausdruck kann auch mit einer runden Startklammer am Anfang einer Zeile beginnen, vorausgesetzt, dass mindestens ein weiteres (
oder )
in der ersten physischen Zeile vorhanden ist. Zum Beispiel könnte der gesamte Ausdruck mit ((
und ))
umschlossen werden.
Abgesehen vom obigen Fall wird beim Vorhandensein ungültiger Optionen ein Ladezeitfehler angezeigt, anstatt die ungültigen Optionen zu ignorieren.
Zeilen, die mit (
beginnen und mit :
enden, sind nicht ausgeschlossen, einen Fortsetzungsbereich zu beginnen, weil sie wie ein Label aussehen, da (
in einem Labelnamen nicht mehr gültig ist. Dies ermöglicht es, dass so etwas wie (Join:
einen Fortsetzungsbereich beginnen kann. (:
ist jedoch ein Fehler und (::
ist immer noch ein Hotkey.
In Ausdrücken und Funktions-/Eigenschaftsdefinitionen wird eine neue Methode der Zeilenfortsetzung unterstützt, die sich die Tatsache zunutze macht, dass jedes (
/[
/{
ein passendes )
/]
/}
haben muss. Mit anderen Worten, wenn eine Zeile ein ungeschlossenes (
/[
/{
enthält, wird sie mit nachfolgenden Zeilen verbunden, bis die Anzahl der Start- und Endklammern ausgeglichen ist. Ein {
am Ende einer Zeile wird als OTB interpretiert (und nicht als Beginn eines direkt geschriebenen Objekts), wenn es keine anderen ungeschlossenen Symbole gibt und kein Operator unmittelbar vor der Klammer steht.
Die Zeilenfortsetzung ist jetzt selektiver hinsichtlich dessen, in welchem Kontext ein Symbol als Ausdrucksoperator interpretiert wird. Grundsätzlich können Komma- und Ausdrucksoperatoren nicht mehr zur Fortsetzung in textueller Hinsicht verwendet werden, z.B. bei Hotstrings oder Direktiven (außer #HotIf) oder nach einer ungeschlossenen, in Anführungszeichen gesetzten Zeichenkette.
Die Zeilenfortsetzung funktioniert nun auch für Ausdrucksoperatoren am Ende einer Zeile.
is
, in
und contains
können für die Zeilenfortsetzung verwendet werden, allerdings sind in
und contains
noch nicht als Operatoren reserviert/implementiert.
and
, or
, is
, in
und contains
fungieren als Zeilenfortsetzungsoperatoren, auch dann, wenn eine Zuweisung oder ein anderer binärer Operator folgt, da sie keine gültigen Variablennamen mehr sind. AHK v1 hingegen hatte Ausnahmen für and
/or
gefolgt von einem der folgenden Zeichen: <>=/|^:,
Wenn .
für die Fortsetzung verwendet wird, werden die beiden Zeilen nicht mehr automatisch durch ein Leerzeichen separiert, wenn am Anfang einer Zeile kein Leer- oder Tabulatorzeichen rechts von .
steht, wie in .SehrLangerVerschachtelterKlassenname
. Beachten Sie, dass x .123
immer ein Eigenschaftszugriff ist (keine Auto-Verkettung) und dass x+.123
mit oder ohne Leerzeichen funktioniert.
In der Regel erzeugt v2 konsistentere Ergebnisse als v1 bei einem Code, der vom Typ eines Wertes abhängt.
In v1 kann eine Variable sowohl eine Zeichenkette als auch eine zwischengespeicherte Binärzahl enthalten, die jedes Mal aktualisiert wird, wenn die Variable als Zahl verwendet wird. Da diese zwischengespeicherte Binärzahl die einzige Möglichkeit ist, den Typ des Wertes zu erkennen, ändert die interne Zwischenspeicherung durch Ausdrücke wie Var+1
oder Abs(Var)
quasi als Nebeneffekt den "Typ" von Var
. AutoHotkey v2 deaktiviert diese Zwischenspeicherung, so dass str := "123"
immer eine Zeichenkette und int := 123
immer ein Integer ist. Folglich muss str
jedes Mal umgewandelt werden, wenn es als Zahl verwendet wird (nicht nur beim ersten Mal), es sei denn, es wurde ursprünglich eine reine Zahl zugewiesen.
Die internen "Variablen" True
, False
, A_PtrSize
, A_Index
und A_EventInfo
geben immer einen reinen Integer zurück, keine Zeichenkette. In v1 geben sie manchmal eine Zeichenkette zurück, bedingt durch bestimmte Optimierungen, die in v2 überflüssig gemacht wurden.
Alle direkt geschriebenen Zahlen werden beim Laden des Skripts in reine Binärzahlen umgewandelt und ihre Zeichenkettendarstellung wird verworfen. Zum Beispiel ist MsgBox 0x1
äquivalent zu MsgBox 1
, während MsgBox 1.0000
äquivalent zu MsgBox 1.0
ist (weil sich die interne Float-Formatierung geändert hat). Eine Zahl, die in eine Variable gespeichert oder von einer benutzerdefinierten Funktion zurückgegeben wird, behält ihren rein numerischen Status.
Das Standardformat für Floating-Point-Zahlen ist nun .17g
(ehemals 0.6f
), was in vielen Fällen kompakter und genauer ist. Dieser Standard kann nicht geändert werden, allerdings kann Format
verwendet werden, um Formatierungen gezielt zu ändern.
Direkt geschriebene, in Anführungszeichen gesetzte Zeichenketten und Zeichenketten, die durch Verkettung mit direkt geschriebenen, in Anführungszeichen gesetzten Zeichenketten erzeugt wurden, werden nicht mehr bedingungslos als nicht-numerisch betrachtet. Stattdessen werden sie wie Zeichenketten behandelt, die in Variablen gespeichert sind oder von Funktionen zurückgegeben werden. Dies hat folgende Auswirkungen:
"0"
wird als False behandelt.("0xA") + 1
und ("0x" Chr(65)) + 1
erzeugen 11 anstatt zu scheitern.x[y:="0"]
und x["0"]
verhalten sich nun gleich.Die Operatoren =
und !=
vergleichen ihre Operanden nun alphabetisch, wenn beide Operanden Zeichenketten sind, sogar wenn sie numerische Zeichenketten sind. Ein numerischer Vergleich wird weiterhin durchgeführt, wenn beide Operanden numerisch sind und mindestens einer von ihnen eine reine Zahl (keine Zeichenkette) ist. Zum Beispiel werden 54
und "530"
numerisch verglichen, während "54"
und "530"
alphabetisch verglichen werden. Außerdem werden in Variablen gespeicherte Zeichenketten genauso behandelt wie direkt geschriebene Zeichenketten.
Die Vergleichsoperatoren <
, <=
, >
und >=
lösen nun eine Ausnahme aus, wenn sie mit einer nicht-numerischen Zeichenkette verwendet werden. Früher verglichen sie numerisch oder alphabetisch, je nachdem, ob beide Eingabewerte numerisch waren, während direkt geschriebene, in Anführungszeichen gesetzte Zeichenketten immer als nicht-numerisch betrachtet wurden. Verwenden Sie stattdessen StrCompare(a, b, GroßKleinSensitiv)
.
Type(Wert)
gibt eine der folgenden Zeichenketten zurück: String, Integer, Float, oder die spezifische Klasse eines Objekts.
Float(Wert)
, Integer(Wert)
und String(Wert)
wandeln Wert in den entsprechenden Typ um, oder lösen eine Ausnahme aus, wenn die Umwandlung nicht möglich ist (z.B. Integer("1z")
). Number(Wert)
wandelt einen Wert in einen Integer oder eine Floating-Point-Zahl um. String(Wert)
ruft Wert.ToString()
auf, wenn Wert ein Objekt ist. (Idealerweise sollte dies für jede implizite Umwandlung von Objekt zu Zeichenkette erfolgen, aber die derzeitige Implementierung macht dies schwierig.)
Objekte verwenden nun einen strukturierteren Klassen-Prototypen-Ansatz, der Klassenelemente bzw. statische Elemente von Instanzelementen trennt. Viele der internen Methoden und Obj-Funktionen wurden verschoben, umbenannt, geändert oder entfernt.
static
definiert wurden (einschließlich der von der Basisklasse geerbten statischen Elemente), und verschachtelte Klassen zur Verfügung stellt.base
(Basis) aller Instanzen dieser Klasse wird. Alle nicht-statischen Methoden- und Eigenschaftsdefinitionen innerhalb des Klassenkörpers sind mit dem Prototypobjekt verbunden.meineKlasse.Call()
oder meineKlasse()
. Dadurch kann die Klasse das Konstruktionsverhalten vollständig überschreiben (z.B. um eine Class Factory oder ein Singleton zu implementieren oder um ein natives Array oder Map anstelle von Object zu konstruieren), obwohl die Initialisierung typischerweise noch in __New
durchgeführt werden sollte. Der Rückgabewert von __New
wird nun ignoriert; um den Rückgabewert zu überschreiben, verwenden Sie die Call-Methode.Der gemischte Objekttyp wurde in Object
, Array
und Map
(assoziatives Array) aufgeteilt.
Object ist nun die Basisklasse für alle benutzerdefinierten und internen Objekte (außer VarRef und COM-Objekte). Elemente, die zu Object.Prototype
hinzugefügt werden, werden von allen AutoHotkey-Objekten geerbt.
Der is
-Operator erwartet eine Klasse, daher prüft x is y
, ob y.Prototype
in der Basisobjektkette existiert. Um zu prüfen, ob y selbst existiert, rufen Sie x.HaseBase(y)
oder HasBase(x, y)
auf.
Benutzerdefinierte Klassen können auch explizit Object
, Array
, Map
oder einige andere interne Klassen via "extends" erweitern (obwohl dies nicht immer sinnvoll ist), wobei Object
die Standardbasisklasse ist, wenn keine angegeben ist.
Der new
-Operator wurde entfernt. Lassen Sie stattdessen einfach den Operator weg, wie in MeineKlasse()
. Um ein Objekt zu konstruieren, das auf einem anderen Objekt basiert, das keine Klasse ist, erstellen Sie es mit {}
oder Object()
(oder auf andere Weise) und setzen Sie dessen base
. __Init
und __New
können bei Bedarf explizit aufgerufen werden, allerdings ist das in der Regel nur bei der Instanziierung einer Klasse sinnvoll.
Verschachtelte Klassendefinitionen erzeugen jetzt eine dynamische Eigenschaft mit Get- und Call-Akzessorfunktionen anstelle einer einfachen Werteigenschaft. Damit soll folgendes Verhalten unterstützt werden:
Verschachtelt.Klasse()
übergibt Verschachtelt nicht an Verschachtelt.Klasse.Call
und letztlich an __New
, was sonst passieren würde, da dies das normale Verhalten für Funktionsobjekte ist, die als Methoden aufgerufen werden (so wie die verschachtelte Klasse hier verwendet wird).Verschachtelt.Klasse := 1
ist standardmäßig ein Fehler (die Eigenschaft ist schreibgeschützt).GetCapacity und SetCapacity wurden entfernt.
Andere redundante Obj-Funktionen (die interne Methoden von Object widerspiegeln) wurden entfernt. ObjHasOwnProp (ehemals ObjHasKey) und ObjOwnProps (ehemals ObjNewEnum) bleiben, um eine sichere Überprüfung von Objekten zu ermöglichen, die solche Methoden neu definiert haben (und die primitiven Prototypen, die diese Methoden nicht definiert haben). ObjCount wurde mit ObjOwnPropCount ersetzt (nur eine Funktion, für alle Objects). Map hat seine eigene Count-Eigenschaft.
ObjRawGet und ObjRawSet wurden mit GetOwnPropDesc und DefineProp zusammengeführt. Die ursprünglichen Gründe für ihr Dasein wurden durch andere Änderungen überflüssig gemacht, z.B. das Map
-Objekt, Änderungen in der Funktionsweise von Metafunktionen, und DefineProp selbst, das Metafunktionen für einige Zwecke überflüssig gemacht hat.
Top-Level-Klassendefinitionen erstellen nun eine Konstante (schreibgeschützte Variable), d.h. Wertzuweisungen an einen Klassennamen zeigen nun einen Fehler statt einer optionalen Warnung an, es sei denn, eine lokale Variable "überschreibt" die globale Klasse (was nun standardmäßig bei Zuweisungen innerhalb einer Funktion geschieht).
Primitive Werte emulieren Objekte durch Delegation von Methoden- und Eigenschaftsaufrufen an ein Prototypobjekt basierend auf ihrem Typ, anstelle des "Standardbasisobjekts" von v1. Integer und Float erweitern (extend) Number. String und Number erweitern Primitive. Primitive und Object erweitern Any. All diese existieren als vordefinierte Klassen.
Methoden werden über Eigenschaften definiert, im Gegensatz zu v2.0-a104 bis v2.0-a127, wo Methoden und Eigenschaften getrennt behandelt werden. Im Gegensatz zu v1 sind jedoch Eigenschaften, die mit einer Klassenmethodendefinition (oder einer internen Methode) erstellt wurden, standardmäßig schreibgeschützt. Methoden können weiterhin durch Zuweisung neuer Werteigenschaften erstellt werden, was grundsätzlich dem Verhalten von v1 entspricht.
Die Object-Klasse definiert neue Methoden für den Umgang mit Eigenschaften und Methoden: DefineProp, DeleteProp, GetOwnPropDesc, HasOwnProp, OwnProps. Zusätzliche Methoden sind für alle Werte (außer ComObjects) definiert: GetMethod, HasProp, HasMethod.
Object, Array und Map sind nun separate Typen, und Array-Elemente und Eigenschaften werden getrennt behandelt.
Die Definition von benutzerdefinierten und internen Methoden/Eigenschaften (einschließlich base
) ist identisch. Dies gewährleistet ein konsistentes Verhalten und erlaubt das Erkennen, Abrufen und Umdefinieren von internen und benutzerdefinierten Elementen.
Wenn eine Eigenschaft keine Parameter akzeptiert, werden diese automatisch an das von der Eigenschaft zurückgegebene Objekt übergeben (oder sie löst eine Ausnahme aus).
Der Versuch, eine nicht-existierende Eigenschaft abzurufen, wird für alle Typen von Werten oder Objekten als Fehler behandelt, es sei denn, __get
wurde definiert. Das Setzen einer nicht-existierenden Eigenschaft wird diese jedoch in den meisten Fällen erstellen.
Hacks für mehrdimensionale Arrays wurden entfernt. x.y[z]:=1
erstellt kein Objekt mehr in x.y
, und x[y,z]
ist ein Fehler, es sei denn, x.__item (oder x.__item.__item usw.) behandelt zwei Parameter.
Wenn eine Eigenschaft get
, aber nicht set
definiert, löst die Zuweisung eines Wertes eine Ausnahme aus, anstatt die Eigenschaft zu überschreiben.
DefineProp kann verwendet werden, um zu definieren, was passieren soll, wenn eine bestimmte Eigenschaft abgerufen, gesetzt oder aufgerufen wird, ohne Metafunktionen definieren zu müssen. Eigenschafts- und Methodendefinitionen in Klassen nutzen denselben Mechanismus, daher kann ein Eigenschafts-Getter/Setter und eine Methode mit demselben Namen definiert werden.
Direkt geschriebene Objekte via {}
setzen nun direkt eigene Eigenschaften oder das base
des Objekts. Das heißt, dass __Set
und Eigenschafts-Setter nicht mehr indirekt aufgerufen werden (was typischerweise nur möglich wäre, wenn base
in der Parameterliste gesetzt ist).
Initialisierungen von statischen bzw. Klassenvariablen werden jetzt im Kontext einer static __Init
-Methode ausgeführt, d.h. this
verweist auf die Klasse und die Initialisierungen können lokale Variablen erstellen. Sie werden evaluiert, wenn die Klasse zum ersten Mal referenziert wird (anstatt vor Beginn des automatischen Ausführungsbereichs, streng in der Reihenfolge der Definition). Wenn die Klasse noch nicht referenziert wurde, werden sie spätestens dann evaluiert, wenn die Klassendefinition während der Ausführung erreicht wird, d.h. die Initialisierung globaler Variablen kann zuerst erfolgen, ohne sie in eine Klasse zu stecken.
Die Metafunktionen wurden stark vereinfacht; sie verhalten sich wie normale Methoden:
super.__xxx()
bei Bedarf aufrufen.return
verwendet (aber natürlich müssen __get und __call immer noch einen Wert zurückgeben).Methoden- und Eigenschaftsparameter werden als Array übergeben. Dies optimiert verkettete Basisaufrufe oder Superklassenaufrufe und ermutigt Autoren (in Kombination mit der MaxParams-Validierung), die Parameter zu behandeln. Bei __set wird der Zuweisungswert separat übergeben.
this.__call(name, args) this.__get(name, args) this.__set(name, args, value)
Definierte Eigenschaften und Methoden haben Vorrang vor Metafunktionen, egal ob sie in einem Basisobjekt definiert wurden.
__Call wird nicht für interne Aufrufe von __Enum (ehemals _NewEnum) oder Call aufgerufen, z.B. wenn ein Objekt an eine For-Schleife übergeben wird oder wenn ein Funktionsobjekt durch SetTimer aufgerufen wird.
Die statische __New-Methode wird für jede Klasse bei ihrer Initialisierung aufgerufen, wenn sie von dieser Klasse definiert oder von einer Superklasse geerbt wurde. Weitere Informationen finden Sie unter Statische bzw. Klassenvariablen (oben) und Klasseninitialisierung.
class Array extends Object
Ein Array-Objekt enthält eine Liste oder Sequenz von Werten, wobei Index 1 das erste Element ist.
Beim Zuweisen oder Abrufen eines Array-Elements muss der Absolutwert des Index zwischen 1 und Length des Arrays liegen, andernfalls wird eine Ausnahme ausgelöst. Die Größe eines Arrays kann durch Einfügen oder Entfernen von Elementen mit der entsprechenden Methode oder durch Zuweisung eines Wertes an Length geändert werden.
Aktuell sind eckige Klammern für den Zugriff auf Elemente erforderlich, d.h. a.1
bezieht sich auf eine Eigenschaft und a[1]
auf ein Element.
Negative Werte können verwendet werden, um rückwärts zu indexieren.
Die Verwendung von Clone, Delete, InsertAt, Pop, Push und RemoveAt ist grundsätzlich gleich geblieben. HasKey wurde umbenannt in Has. Length ist nun eine Eigenschaft. Die Capacity-Eigenschaft wurde hinzugefügt.
Arrays können mit Array(Werte*)
oder [Werte*]
konstruiert werden. Variadische Funktionen erhalten ein Array von Parametern. Einige interne Funktionen erstellen ein Array.
Die For-Schleife-Verwendung ist for val in arr
oder for idx, val in arr
, wobei standardmäßig idx = A_Index
ist. Das bedeutet, dass Elemente ohne Wert weiterhin enumeriert werden und dass der Index nicht zurückgegeben wird, wenn nur eine Variable übergeben wurde.
Ein Map-Objekt ist ein assoziatives Array mit ähnlichen Fähigkeiten wie das v1-Objekt, aber weniger Mehrdeutigkeit.
Derzeit werden Float-Schlüssel noch in Zeichenketten umgewandelt.
Eckige Klammern sind für den Zugriff auf Elemente erforderlich, d.h. a.b
bezieht sich auf eine Eigenschaft und a["b"]
auf ein Element. Im Gegensatz zu v1 kann eine Eigenschaft oder Methode nicht versehentlich durch die Zuweisung eines Array-Elements deaktiviert werden.
Es wird eine Ausnahme ausgelöst, wenn versucht wird, den Wert eines nicht-existierenden Elements abzurufen, es sei denn, das Map-Objekt hat eine Default-Eigenschaft definiert. MapObj.Get(Schlüssel, Standardwert)
kann verwendet werden, um explizit einen Standardwert für jeden Abruf bereitzustellen.
Verwenden Sie Map(Schlüssel, Wert, ...)
, um ein Map-Objekt anhand einer Liste von Schlüssel-Wert-Paaren zu erstellen.
Geändertes Enumerator-Modell:
Call(&a)
definiert ist, a := next_value
zuweisen, während Call(a)
ein VarRef erhalten würde und somit %a% := next_value
zuweisen sollte.Da Array-Elemente und Eigenschaften nun getrennt behandelt werden, muss zum Enumerieren von Eigenschaften explizit ein Enumerator via OwnProps erstellt werden.
Wenn eine Bound-Funktion aufgerufen wird, belegen die vom Aufrufer übergebenen Parameter alle Positionen, die bei der Erstellung der Bound-Funktion weggelassen wurden. Zum Beispiel bewirkt F.Bind(,b).Call(a,c)
, dass F(a,b,c)
statt F(,b,a,c)
aufgerufen wird.
COM-Wrapper-Objekte werden jetzt in Abhängigkeit von ihrem Variantentyp als Instanzen einiger verschiedener Klassen identifiziert (was wie früher Auswirkungen darauf hat, welche Methoden und Eigenschaften sie unterstützen):
ComValue
ist die Basisklasse für alle COM-Wrapper-Objekte.ComObject
ist für VT_DISPATCH mit einem Nicht-Null-Pointer, was typischerweise ein gültiges COM-Objekt ist, das vom Skript mit normaler Objektsyntax indirekt aufgerufen werden kann.ComObjArray
ist für VT_ARRAY (SafeArrays).ComValueRef
ist für VT_BYREF.Diese Klassen können für Typprüfungen mit obj is ComObject
und ähnlichem verwendet werden. Für Objekte vom Typ ComValue, ComObjArray und ComValueRef (aber nicht ComObject) können Eigenschaften und Methoden durch Ändern des entsprechenden Prototypobjekts definiert werden.
ComObject(CLSID)
erstellt ein ComObject; dies ist quasi das neue ComObjCreate.
Hinweis: Wenn Sie alten Code aktualisieren und einen TypeError erhalten, weil ein Integer an ComObject übergeben wurde, sollten Sie wahrscheinlich stattdessen ComValue aufrufen.
ComValue(vt, Wert)
erstellt ein Wrapper-Objekt. Es kann eine Instanz einer der oben aufgeführten Klassen zurückgeben. Dies ersetzt ComObjParameter(vt, value)
, ComObject(vt, value)
und alle anderen Namen, die mit einem Variantentyp und Wert als Parameter verwendet wurden. Wert wird in den entsprechenden Typ umgewandelt (gemäß COM-Konventionen), anstatt einen Integer mit dem richtigen Binärwert zu verlangen. Genauer gesagt verhalten sich die folgenden anders als früher, wenn ihnen ein Integer übergeben wird: R4, R8, Cy, Date. Pointertypen erlauben entweder eine reine Integeradresse wie früher oder ein Objekt/ComValue.
ComObjFromPtr(pdsp)
ist eine ähnliche Funktion wie ComObjEnwrap(dsp)
, aber wie ObjFromPtr ruft sie nicht AddRef auf den Pointer auf. Das v1-Äquivalent ist ComObject(9, dsp, 1)
; das Weglassen des dritten Parameters in v1 führte zu AddRef.
Sowohl bei ComValue als auch bei ComObjFromPtr ist zu beachten, dass AddRef nie automatisch aufgerufen wird; in dieser Hinsicht verhalten sie sich wie ComObject(9, Wert, 1)
oder ComObject(13, Wert, 1)
in v1. Dies bedeutet nicht unbedingt, dass Sie ObjAddRef(Wert)
beim Aktualisieren alter Skripte hinzufügen sollten, da viele Skripte die alte Funktion falsch verwendet haben.
COM-Wrapper-Objekte mit dem Variantentyp VT_BYREF, VT_ARRAY oder VT_UNKNOWN haben jetzt eine Ptr-Eigenschaft äquivalent zu ComObjValue(ComObj)
. Dadurch können sie an DllCall oder ComCall mit dem Argumenttyp Ptr übergeben werden. Außerdem kann dadurch das Objekt direkt an NumPut oder NumGet übergeben werden, was zusammen mit VT_BYREF (Zugriff auf die typisierte Variable des Aufrufers), VT_ARRAY (Zugriff auf SAFEARRAY-Felder) oder VT_UNKNOWN (vtable-Pointer abrufen) verwendet werden kann.
COM-Wrapper-Objekte mit dem Variantentyp VT_DISPATCH oder VT_UNKNOWN und einem Null-Interface-Pointer haben jetzt eine Ptr-Eigenschaft, die gelesen oder geändert werden kann. Sobald ihr ein Nicht-Null-Pointer zugewiesen wurde, ist die Eigenschaft schreibgeschützt. Dies ist für die Verwendung mit DllCall und ComCall vorgesehen, damit der Pointer nach dem Return der Funktion nicht manuell gewrappt werden muss.
Die Enumeration von ComObjArray ist jetzt konsistent mit Array, d.h. for value in arr
oder for index, value in arr
statt for value, vartype in arr
. Der Startwert für index ist die Untergrenze von ComObjArray (arr.MinIndex()
), typischerweise 0.
Die Integertypen I1, I8, UI1, UI2, UI4 und UI8 werden nun in einen Integer statt in eine Zeichenkette umgewandelt. Diese kommen in COM-Aufrufen selten vor, was auch für VT_BYREF-Wrapper gilt. VT_ERROR wird nicht mehr in einen Integer umgewandelt, sondern erzeugt einen ComValue.
COM-Objekte setzen nicht mehr A_LastError, wenn ein indirekter Eigenschafts- oder Methodenaufruf fehlschlägt.
Ein COM-Objekt kann eine "Standardeigenschaft" haben, die zwei Verwendungen hat:
MsgBox obj
in VBScript das Objekt durch indirekten Aufruf seines Standardelements.AutoHotkey v1 hatte kein Konzept für eine Standardeigenschaft, so dass der COM-Objekt-Wrapper die Standardeigenschaft indirekt aufrief, wenn der Eigenschaftsname weggelassen wurde, also obj[]
oder obj[,x]
.
AutoHotkey v2 trennt jedoch Eigenschaften von Array-/Map-/Collection-Elementen, indem obj[x]
auf die Standardeigenschaft des Objekts gemappt wird (egal ob x vorhanden ist oder nicht). Für AutoHotkey-Objekte ist dies __Item
.
Einige COM-Objekte, die Arrays oder Collections repräsentieren, stellen keine Standardeigenschaft zur Verfügung, so dass es in v2 nicht möglich ist, mit []
auf Elemente zuzugreifen. Zum Beispiel stellen JavaScript-Array-Objekte und einige andere Objekte, die normalerweise mit JavaScript verwendet werden, Array-Elemente als Eigenschaften zur Verfügung. In solchen Fällen kann arr.%i%
verwendet werden, um auf eine Array-Element-Eigenschaft zuzugreifen.
Wenn ein Array-Objekt von AutoHotkey v2 an JavaScript übergeben wird, können seine Elemente nicht mit JavaScripts arr[i]
abgerufen werden, da dies einen Zugriffsversuch auf eine Eigenschaft bedeuten würde.
Aufrufe von AutoHotkey-Objekten über das IDispatch-Interface unterstützen jetzt nachvollziehbar VT_BYREF-Parameter. Dies wird häufig mit COM-Ereignissen verwendet (ComObjConnect).
Für jeden VT_BYREF-Parameter wird eine namenlose temporäre Variable erstellt, der Wert aus der Variable des Aufrufers kopiert und eine VarRef an die AutoHotkey-Funktion/Methode übergeben. Bei Return wird der Wert aus der temporären Variable zurück in die Variable des Aufrufers kopiert.
Eine Funktion/Methode kann einen Wert durch Deklaration des Parameters als ByRef (mit &
) oder durch explizite Dereferenzierung zuweisen.
Zum Beispiel würde ein Parameter vom Typ VT_BYREF|VT_BOOL
vorher ein ComObjRef-Objekt erhalten und einen Wert wie pbCancel[] := true
oder NumPut(-1, ComObjValue(pbCancel), "short")
zugewiesen bekommen. Nun kann der Parameter als &bCancel
definiert und zugewiesen werden, z.B. bCancel := true
; oder als pbCancel
definiert und zugewiesen werden, z.B. %pbCancel% := true
.
Entfernt | Hinweis |
---|---|
Asc() | Verwenden Sie stattdessen Ord. |
AutoTrim | Verwenden Sie stattdessen Trim. |
ComObjMissing() | Schreiben Sie stattdessen zwei aufeinanderfolgende Kommas. |
ComObjUnwrap() | Verwenden Sie stattdessen ComObjValue und ggf. ObjAddRef. |
ComObjEnwrap() | Verwenden Sie stattdessen ComObjFromPtr und ggf. ObjAddRef. |
ComObjError() | |
ComObjXXX() | Wenn XXX nichts anderes als eine der explizit definierten ComObj-Funktionen ist, verwenden Sie stattdessen ComObjActive, ComValue oder ComObjFromPtr. |
ControlSendRaw | Verwenden Sie stattdessen ControlSend "{Raw}" oder ControlSendText. |
EnvDiv | Verwenden Sie stattdessen / oder /= , z.B. a /= b . |
EnvMult | Verwenden Sie stattdessen * oder *= , z.B. a *= b . |
EnvUpdate | Es ist von sehr begrenztem Nutzen und kann wie folgt mit einem einfachen SendMessage ersetzt werden: SendMessage(0x1A, 0, StrPtr("Environment"), 0xFFFF) . |
Exception | Verwenden Sie stattdessen Error oder eine geeignete Unterklasse. |
FileReadLine | Verwenden Sie stattdessen eine dateilesende Schleife oder FileOpen. |
Func | Verwenden Sie stattdessen eine direkte Referenz wie MeineFunk . |
Gosub | |
Gui GuiControl GuiControlGet |
Siehe Gui weiter unten. |
IfEqual | Verwenden Sie stattdessen If und = , z.B. if a = b . |
IfExist | Verwenden Sie stattdessen If und FileExist, z.B. if FileExist(...) . |
IfGreater | Verwenden Sie stattdessen If und > , z.B. if a > b . |
IfGreaterOrEqual | Verwenden Sie stattdessen If und >= , z.B. if a >= b . |
IfInString | Verwenden Sie stattdessen If und InStr, z.B. if InStr(...) . |
IfLess | Verwenden Sie stattdessen If und < , z.B. if a < b . |
IfLessOrEqual | Verwenden Sie stattdessen If und <= , z.B. if a <= b . |
IfMsgBox | MsgBox gibt nun den Namen der Schaltfläche zurück. |
IfNotEqual | Verwenden Sie stattdessen If und != , z.B. if a != b . |
IfNotExist | Verwenden Sie stattdessen If und FileExist, z.B. if not FileExist(...) . |
IfNotInString | Verwenden Sie stattdessen If und InStr, z.B. if not InStr(...) . |
IfWinActive | Verwenden Sie stattdessen If und WinActive, z.B. if WinActive(...) . |
IfWinExist | Verwenden Sie stattdessen If und WinExist, z.B. if WinExist(...) . |
IfWinNotActive | Verwenden Sie stattdessen If und WinActive, z.B. if not WinActive(...) . |
IfWinNotExist | Verwenden Sie stattdessen If und WinExist, z.B. if not WinExist(...) . |
If between | Siehe If-Beispiel #5. |
If in/contains | Siehe If-Beispiel #6. |
If is | Siehe isXXX weiter unten. |
Input | Verwenden Sie stattdessen InputHook. |
IsByRef | Siehe ByRef-Einschränkungen. |
IsFunc | |
Menu | Verwenden Sie stattdessen die Menu/MenuBar-Klasse, TraySetIcon, A_IconTip, A_IconHidden und A_AllowMainWindow. |
MenuGetHandle | Verwenden Sie stattdessen Menu.Handle. |
MenuGetName | Es gibt keine Menünamen; MenuFromHandle ist der nächstbeste Ersatz. |
Progress | Verwenden Sie stattdessen Gui. |
SendRaw | Verwenden Sie stattdessen Send "{Raw}" oder SendText. |
SetBatchLines | -1 ist nun das Standardverhalten. |
SetEnv | Verwenden Sie stattdessen := . |
SetFormat | Format kann zum Formatieren einer Zeichenkette verwendet werden. |
SoundGet SoundSet |
Siehe Sound-Funktionen weiter unten. |
SoundGetWaveVolume SoundSetWaveVolume |
Sie verhalten sich etwas anders als SoundGet und SoundSet in Bezug auf die Balance, aber keines von beiden behält die Balance bei. |
SplashImage | Verwenden Sie stattdessen Gui. |
SplashTextOn/Off | Verwenden Sie stattdessen Gui. |
StringCaseSense | != ist immer nicht-Groß-/Kleinschreibung-sensitiv (allerdings wurde !== für "Groß-/Kleinschreibung-sensitiv ungleich" hinzugefügt). Sowohl = als auch != ignorieren nur die Groß-/Kleinschreibung bei ASCII-Zeichen. StrCompare wurde hinzugefügt, um Zeichenketten in jedem Modus zu vergleichen. Verschiedene String-Funktionen haben jetzt einen GroßKleinSensitiv-Parameter, mit dem die Groß-/Kleinschreibung-Sensitivität oder der Locale-Modus angegeben werden kann. |
StringGetPos | Verwenden Sie stattdessen InStr. |
StringLeft StringLen StringMid StringRight StringTrimLeft StringTrimRight |
Verwenden Sie stattdessen SubStr. |
StringReplace | Verwenden Sie stattdessen StrReplace. |
StringSplit | Verwenden Sie stattdessen StrSplit. |
Transform | Verwenden Sie stattdessen mathematische Funktionen und Operatoren. Für Transform Deref siehe RegExMatch-Beispiel #8. Für Transform HTML siehe Kodierung von HTML-Entitäten. |
VarSetCapacity | Verwenden Sie stattdessen ein Buffer-Objekt für Binärdaten/Strukturen und VarSetStrCapacity für UTF-16-Zeichenketten. |
WinGetActiveStats | Verwenden Sie stattdessen WinGetTitle und WinGetPos. |
WinGetActiveTitle | Verwenden Sie stattdessen WinGetTitle, z.B. WinGetTitle "A" . |
#CommentFlag | |
#Delimiter | |
#DerefChar | |
#EscapeChar | |
#HotkeyInterval | Verwenden Sie stattdessen A_HotkeyInterval. |
#HotkeyModifierTimeout | Verwenden Sie stattdessen A_HotkeyModifierTimeout. |
#IfWinActive #IfWinExist #IfWinNotActive #IfWinNotExist |
Siehe #HotIf-Optimierung. |
#InstallKeybdHook | Verwenden Sie stattdessen InstallKeybdHook. |
#InstallMouseHook | Verwenden Sie stattdessen InstallMouseHook. |
#KeyHistory | Verwenden Sie stattdessen KeyHistory N . |
#LTrim | Verwenden Sie bei Bedarf stattdessen die LTrim-Option. |
#MaxHotkeysPerInterval | Verwenden Sie stattdessen A_MaxHotkeysPerInterval. |
#MaxMem | Die maximale Kapazität jeder Variable ist nun unbegrenzt. |
#MenuMaskKey | Verwenden Sie stattdessen A_MenuMaskKey. |
#NoEnv | Es ist nun das Standardverhalten. |
v1-Name | v2-Name |
---|---|
ComObjCreate() | ComObject, das nun eine Klasse ist |
ComObjParameter() | ComValue, das nun eine Klasse ist |
DriveSpaceFree | DriveGetSpaceFree |
EnvAdd | DateAdd |
EnvSub | DateDiff |
FileCopyDir | DirCopy |
FileCreateDir | DirCreate |
FileMoveDir | DirMove |
FileRemoveDir | DirDelete |
FileSelectFile | FileSelect |
FileSelectFolder | DirSelect |
#If | #HotIf |
#IfTimeout | HotIfTimeout |
StringLower | StrLower und StrTitle |
StringUpper | StrUpper und StrTitle |
UrlDownloadToFile | Download |
WinMenuSelectItem | MenuSelect |
LV-, TV- und SB-Funktionen | Methoden von GuiControl |
File.__Handle | File.Handle |
Die Überschrift soll nicht suggerieren, dass es Befehle in v2 gibt. Es gibt nur Funktionen. Die Überschrift bezieht sich auf beide Versionen.
BlockInput wird nicht mehr kurzzeitig deaktiviert, wenn ein Alt-Ereignis mit der SendEvent-Methode gesendet wird. Dies war ursprünglich notwendig, um einen Bug in einigen Versionen von Windows XP zu umgehen, der BlockInput dazu veranlasste, das künstliche Alt-Ereignis zu blockieren.
Chr(0)
gibt eine Zeichenkette mit der Länge 1 zurück, da eine binäre Null enthalten ist. Dies beruht auf der verbesserten Unterstützung für binäre Nullen in Zeichenketten.
ClipWait gibt nun 0 (false) zurück, wenn die Wartezeit abgelaufen ist, andernfalls 1 (true). ErrorLevel wurde entfernt. Die Angabe von 0 entspricht nicht länger der Angabe von 0.5; stattdessen wird die kleinstmögliche Wartezeit erzeugt.
ComObj()
: Diese Funktion hatte quasi einen Platzhalternamen, der viele verschiedene Suffixe zuließ. Einige Namen wurden häufiger mit bestimmten Parametertypen verwendet, z.B. ComObjActive(CLSID)
, ComObjParameter(vt, value)
, ComObjEnwrap(dsp)
. Stattdessen gibt es jetzt separate Funktionen/Klassen und keine Platzhalternamen mehr. Weitere Informationen finden Sie unter COM-Objekte (ComObject).
Steuerelement-Parameter: Es wurden mehrere Änderungen am Steuerelement-Parameter vorgenommen, der von den Control-Funktionen, SendMessage und PostMessage verwendet wird:
ahk_parent
.ControlGetFocus gibt nun die HWND-Nummer anstelle der ClassNN-Bezeichnung des Steuerelements zurück, und wertet es nicht mehr als Fehler, wenn es erfolgreich festgestellt hat, dass das Fenster kein fokussiertes Steuerelement aufweist.
ControlMove, ControlGetPos und ControlClick verwenden nun Clientkoordinaten (wie GuiControl) statt Fensterkoordinaten. Clientkoordinaten sind relativ zur oberen linken Ecke des Clientbereichs (das ist der Bereich ohne Titelleiste und Rahmen). (Steuerelemente werden nur im Clientbereich gerendert.)
ControlMove, ControlSend und ControlSetText haben nun eine Parameterreihenfolge, die mit anderen Control-Funktionen konsistent ist, d.h. Steuerelement, FensterTitel, FensterText, AusnahmeTitel, AusnahmeText werden immer zusammen in dieser Reihenfolge verwendet (am Ende der Parameterliste), um das Einprägen der Parameter zu fördern.
CoordMode akzeptiert nicht länger "Relative" als Modus, da alle Modi relativ zu etwas sind. Es war synonym mit "Window", verwenden Sie stattdessen dieses Wort.
DllCall: Siehe DllCall-Abschnitt weiter unten.
Edit hatte früher ein Fallback-Verhalten für den Dateityp .ini
, wenn das Shellverb "edit" nicht registriert war. Dies wurde entfernt, da Skriptdateien nicht mehr die Dateiendung .ini
haben können. AutoHotkey.ini
war der Standardskriptname in alten AutoHotkey-Versionen.
Edit macht nun nichts mehr, wenn das Skript aus der Standardeingabe (stdin) gelesen wurde, anstatt zu versuchen, einen Editor für *
zu öffnen.
EnvSet löscht nun die Umgebungsvariable, wenn der Wert-Parameter vollständig weggelassen wird.
Exit verhielt sich früher wie ExitApp, wenn das Skript nicht persistent ist, selbst wenn es andere suspendierte Threads gab, die vom Thread, der Exit aufrief, unterbrochen wurden. Dies ist nun nicht mehr der Fall. Stattdessen wird der aktuelle Thread immer ordnungsgemäß beendet, und das Skript erst terminiert (sofern nicht persistent), wenn der letzte Thread beendet wurde. Dadurch wird sichergestellt, dass Finally-Anweisungen ausgeführt und lokale Variablen freigegeben werden, was wiederum den Aufruf von __Delete
für alle in lokalen Variablen enthaltenen Objekte ermöglicht.
FileAppend übersetzt standardmäßig keine Zeilenumbrüche, um mit FileRead und FileOpen konsistent zu sein. FileAppend und FileRead haben jeweils einen separaten Optionen-Parameter, der die Optionspräfixe ersetzt und optional einen Kodierungsnamen enthalten kann (was die *Pnnn
-Option von FileRead überflüssig macht). FileAppend, FileRead und FileOpen verwenden "`n"
, um Zeilenumbruchübersetzungen zu aktivieren. FileAppend und FileRead unterstützen die Option "RAW"
, um die Codepageumwandlung zu deaktivieren (Binärdaten lesen/schreiben); FileRead gibt in diesem Fall ein Buffer-Objekt zurück. Dies ersetzt *c
(siehe ClipboardAll). FileAppend akzeptiert ein Buffer-ähnliches Objekt, in diesem Fall wird keine Umwandlung durchgeführt.
FileCopy und FileMove lösen jetzt eine Ausnahme aus, wenn der Quellpfad kein *
oder ?
enthält und keine Datei gefunden wurde. Nach wie vor wird das Kopieren oder Verschieben von 0 Dateien nicht als Fehler gewertet, wenn der Quellpfad Platzhalterzeichen enthält.
FileOpen löst jetzt eine Ausnahme aus, wenn die Datei nicht geöffnet werden kann. Andernfalls würde eine Ausnahme bereits beim ersten Zugriffsversuch auf das Objekt ausgelöst (wenn das Skript nicht auf Fehler geprüft hat) und nicht erst am eigentlichen Fehlerpunkt.
File.RawRead: Bei der direkten Übergabe einer Variable wird die Adresse des internen Zeichenkettenpuffers der Variable nicht länger verwendet. Daher kann eine Variable, die eine Adresse enthält, direkt übergeben werden (während in v1 so etwas wie var+0
notwendig war).
Zum Reservieren von Pufferspeicher ist das neue Buffer-Objekt einer Variable vorzuziehen; jedes Objekt kann verwendet werden, solange es die Ptr- und Size-Eigenschaft hat.
File.RawWrite: Wie oben, außer dass es eine Zeichenkette (oder eine Variable mit einer Zeichenkette) akzeptieren kann - in diesem Fall ist Bytes standardmäßig die Größe der Zeichenkette in Bytes. Die Zeichenkette kann binäre Nullen enthalten.
File.ReadLine unterstützt nun immer `r
, `n
und `r`n
als Zeilenenden und fügt das Zeilenende nicht länger in den Rückgabewert ein. Zeilenenden werden weiterhin unverändert via File.Read an das Skript zurückgegeben, wenn die Zeilenumbruchübersetzung deaktiviert ist.
FileEncoding erlaubt nun die Angabe von Codepages als Zahl ohne das Präfix CP
. Der Parameter ist nicht mehr optional, kann aber weiterhin explizit leer sein.
FileExist ignoriert nun .
und ..
implizit in jeder Verzeichnisauflistung, folglich ist FileExist("dir\*")
nun False statt True, wenn das Verzeichnis existiert, aber leer ist.
FileGetAttrib und A_LoopFileAttrib haben jetzt den Buchstaben "L" für Analysepunkte oder symbolische Verknüpfungen.
FileInstall in einem unkompilierten Skript versucht nicht länger, die Datei zu kopieren, wenn Quelle und Ziel derselbe Pfad sind (nach der Auflösung relativer Pfade, da die Quelle relativ zu A_ScriptDir ist, nicht zu A_WorkingDir). In v1 führte dies dazu, dass ErrorLevel auf 1 gesetzt wurde, was meist unbemerkt blieb. Der Versuch, eine Datei mittels zwei verschiedener Pfade auf sich selbst zu kopieren, löst weiterhin einen Fehler aus.
FileSelectFile (jetzt FileSelect) hatte zwei Mehrfachauswahlmodi, die über die Optionen 4 und M zugänglich waren. Option 4 und der entsprechende Modus wurden entfernt; sie waren für einige Zeit undokumentiert. FileSelect gibt nun im Mehrfachauswahlmodus ein Array von Pfaden zurück, anstatt einer Zeichenkette wie C:\Verz`nDatei1`nDatei2
. Jedes Array-Element enthält den vollständigen Pfad einer Datei. Wenn der Benutzer das Dialogfenster abbricht, ist das Array leer.
FileSelect verwendet jetzt die seit Windows Vista verfügbare IFileDialog-API anstelle der alten GetOpenFileName/GetSaveFileName-API. Dadurch entfällt die Notwendigkeit von (internen) Workarounds, die sich darauf beziehen, dass das Dialogfenster das aktuelle Arbeitsverzeichnis ändert.
FileSelect hat nicht mehr standardmäßig den redundanten Filter "Text Documents (*.txt)", wenn Filter weggelassen wird.
FileSelect entfernt keine Leerzeichen mehr aus dem Filtermuster, wie z.B. bei Muster mit Leerzeichen*.ext
. Tests haben gezeigt, dass Leerzeichen auf beiden Seiten des Musters (z.B. nach dem Semikolon in *.cpp; *.h
) bereits vom Betriebssystem ignoriert werden, so dass es keine negativen Auswirkungen geben sollte.
FileSelect kann jetzt im "Ordner auswählen"-Modus mit dem Optionsbuchstaben D
verwendet werden.
FileSetAttrib überschreibt nun Attribute, wenn kein +, - oder ^ als Präfix vorhanden ist, anstatt nichts zu tun. Zum Beispiel kopiert FileSetAttrib(FileGetAttrib(Datei2), Datei1)
die Attribute von Datei2 nach Datei1 (alles was Datei2 hat wird hinzugefügt und alles was Datei2 nicht hat wird entfernt).
FileSetAttrib und FileSetTime: Die Parameter OrdnerEinbeziehen und Rekursiv wurden mit einem einzelnen Modus-Parameter ersetzt, der mit dem von Loop Files identisch ist. Zum Beispiel FileSetAttrib("+a", "*.zip", "RF")
(nur Dateien rekursiv durchwandern).
GetKeyName gibt jetzt die Nicht-Ziffernblock-Namen für VK-Codes zurück, die sowohl einer Ziffernblock- als auch einer Nicht-Ziffernblock-Taste entsprechen. Zum Beispiel gibt GetKeyName("vk25")
Left statt NumpadLeft zurück.
GetKeyState gibt nun immer 1 oder 0 statt On bzw. Off zurück.
GroupActivate gibt nun die HWND-Nummer des Fensters zurück, das für die Aktivierung ausgewählt wurde, oder 0, wenn kein passendes Fenster gefunden wurde (abgesehen vom bereits aktiven Fenster), anstatt ErrorLevel zu setzen.
GroupAdd: Der Label-Parameter und die dazugehörige Funktionalität wurden entfernt. Dies war eine unintuitive Möglichkeit zu erkennen, wenn GroupActivate keine passenden Fenster finden konnte; verwenden Sie stattdessen den Rückgabewert von GroupActivate.
GroupDeactivate selektiert nun Fenster ähnlich der Taskleiste und den System-Hotkeys Alt+Esc und Alt+Umschalt+Esc. Konkret heißt das:
Hotkey verwendet nicht mehr standardmäßig das #HotIf (ehemals #If) ganz unten im Skript. Hotkey/Hotstring- und HotIf-Threads verwenden standardmäßig dasselbe Kriterium wie der Hotkey, folglich schaltet Hotkey A_ThisHotkey, "Off"
den aktuellen Hotkey aus, selbst wenn er kontextabhängig ist. Alle anderen Threads verwenden standardmäßig die zuletzt im automatischen Ausführungsbereich definierte Einstellung, die wiederum standardmäßig keine Kriterien verwendet (globale Hotkeys).
Der Aktion-Parameter von Hotkey benötigt nun ein Funktionsobjekt oder den Namen eines Hotkeys. Labels und Funktionsnamen werden nicht mehr unterstützt. Wenn der Name eines Hotkeys angegeben ist, wird die ursprüngliche Funktion dieses Hotkeys verwendet; und im Gegensatz zu früher funktioniert dies mit #HotIf (ehemals #If).
On
, Off
, Toggle
, AltTab
, ShiftAltTab
, AltTabAndMenu
, AltTabMenuDismiss
. Früher wurde das Label oder die Funktion mit diesem Namen verwendet, sofern vorhanden, aber nur, wenn der Label-Parameter weder eine Variablenreferenz noch einen Ausdruck enthielt.Hotkey und Hotstring unterstützen jetzt die S-Option, um den Hotkey/Hotstring vor Suspend zu schützen (entspricht der neuen Direktive #SuspendExempt), und die S0-Option, um den Schutz zu deaktivieren.
"Hotkey If" und die anderen If-Unterbefehle wurden in einzelne Funktionen aufgeteilt: HotIf, HotIfWinActive, HotIfWinExist, HotIfWinNotActive, HotIfWinNotExist.
HotIf (ehemals "Hotkey If") erkennt nun Ausdrücke, die die Operatoren and
oder or
verwenden. In v1 funktionierte dies nicht, da diese Operatoren beim Laden des Skripts mit &&
oder ||
ersetzt wurden.
Hotkey hat nicht länger die UseErrorLevel-Option und wird niemals ErrorLevel setzen. Bei Misserfolg wird eine Ausnahme ausgelöst. Die Fehlermeldungen wurden geändert, um konstant (und kürzer) zu sein, mit der Taste oder dem Namen des Hotkeys in Exception.Extra
, und mit der Klasse der Ausnahme, die den Grund für den Fehler angibt.
#HotIf (ehemals #If) erstellt jetzt implizit eine Funktion mit einem Parameter (ThisHotkey). Wie alle Funktionen ist auch diese Funktion standardmäßig eine Assume-Local-Funktion. Der Ausdruck kann lokale Variablen erstellen und globale Variablen lesen, aber nicht direkt globalen Variablen etwas zuweisen, da der Ausdruck keine Deklarationen enthalten kann.
#HotIf wurde so optimiert, dass einfache Aufrufe von WinActive oder WinExist direkt vom Hook-Thread ausgewertet werden können (wie es bei #IfWin in v1 der Fall war und bei HotIfWin immer noch der Fall ist). Dies verbessert die Performanz und verringert das Risiko von Problemen, wenn das Skript beschäftigt ist oder nicht reagiert. Diese Optimierung gilt für Ausdrücke, die einen einzelnen Aufruf von WinActive oder WinExist mit bis zu zwei Parametern enthalten, wobei jeder Parameter eine einfache in Anführungszeichen gesetzte Zeichenkette ist und das Ergebnis optional mit !
oder not
invertiert wird. Zum Beispiel #HotIf WinActive("Chrome")
oder #HotIf !WinExist("Popup")
. In solchen Fällen kann der erste Ausdruck mit einer beliebigen Kombination von Kriterien entweder via Ausdruck oder via Fensterkriterien identifiziert werden. Zum Beispiel verweisen HotIf '!WinExist("Popup")'
und HotIfWinNotExist "Popup"
auf dieselben Hotkey-Varianten.
KeyHistory N
ändert die Größe des Tastenverlaufspuffers, anstatt den Tastenverlauf anzuzeigen. Dies ersetzt "#KeyHistory N".
ImageSearch gibt 1 (true) zurück, wenn das Bild gefunden wurde, oder 0 (false), wenn es nicht gefunden wurde, und löst eine Ausnahme aus, wenn die Suche nicht durchgeführt werden konnte. ErrorLevel wird nicht gesetzt.
IniDelete, IniRead und IniWrite setzen A_LastError auf das Ergebnis der Systemfunktion GetLastError().
IniRead löst eine Ausnahme aus, wenn der Schlüssel, die Sektion oder die Datei nicht gefunden werden kann und der Standardwert-Parameter weggelassen wurde. Wenn ein Standardwert angegeben wurde, sogar ""
, wird keine Ausnahme ausgelöst.
InputHook behandelt nun Umschalt+Backspace wie Backspace, anstatt es in `b
zu übersetzen.
InputBox wurde syntaktisch überarbeitet, um die Benutzerfreundlichkeit zu verbessern (weniger Parameter). Informationen zur Verwendung finden Sie unter InputBox.
InStr: Der GroßKleinSensitiv-Parameter akzeptiert jetzt 0, 1 oder "Locale".
InStr sucht jetzt von rechts nach links, wenn Vorkommen negativ ist (was früher zu einem Ergebnis von 0 führte), und sucht nicht mehr von rechts nach links, wenn eine negative StartPos mit einem positiven Vorkommen verwendet wird. (InStr sucht jedoch weiterhin von rechts nach links, wenn StartPos negativ ist und Vorkommen weggelassen wird.) Dies unterstützt die Rechts-nach-Links-Suche in einer Schleife und ermöglicht es, eine negative StartPos zu verwenden und trotzdem von links nach rechts zu suchen.
InStr(a, b,, -1, 2)
jetzt von links nach rechts. Um stattdessen von rechts nach links zu suchen, verwenden Sie InStr(a, b,, -1, -2)
.InStr(a, b, -2, -2)
sein.KeyWait gibt nun 0 (false) zurück, wenn die Wartezeit abgelaufen ist, andernfalls 1 (true). ErrorLevel wurde entfernt.
MouseClick und MouseClickDrag sind nicht mehr von der Systemeinstellung zum Vertauschen der Maustasten betroffen; "Left" ist immer die primäre Taste und "Right" immer die sekundäre Taste.
MsgBox wurde syntaktisch geändert, um seine häufig verwendeten Parameter zu priorisieren und die Benutzerfreundlichkeit zu verbessern. Informationen zur Verwendung finden Sie unter MsgBox weiter unten.
NumPut/NumGet: Bei der direkten Übergabe einer Variable wird die Adresse des internen Zeichenkettenpuffers der Variable nicht länger verwendet. Daher kann eine Variable, die eine Adresse enthält, direkt übergeben werden (während in v1 so etwas wie var+0
notwendig war). Zum Reservieren von Pufferspeicher ist das neue Buffer-Objekt einer Variable vorzuziehen; jedes Objekt kann verwendet werden, solange es die Ptr- und Size-Eigenschaft hat.
Die Parameter von NumPut wurden neu angeordnet, um die Angabe einer Sequenz von Werten zu ermöglichen, wobei jeder Zahl eine Zeichenkette vorangestellt werden muss, die den Typ der Zahl angibt. Zum Beispiel: NumPut("ptr", a, "int", b, "int", c, addrOrBuffer, offset)
. Auch der Typ-Parameter von NumGet kann nicht mehr weggelassen werden. (Im Vergleich zu DllCall entsprechen die Eingabeparameter von NumPut den Parametern der DLL-Funktion, während der Rückgabetypparameter von NumGet der Rückgabetypzeichenkette der DLL-Funktion entspricht.)
Die Verwendung von Object(obj)
und Object(ptr)
zum Umwandeln zwischen einer Referenz und einem Pointer sind nun separate Funktionen: ObjPtrAddRef(obj)
und ObjFromPtrAddRef(ptr)
. Es gibt auch Versionen dieser Funktionen, die die Referenzanzahl nicht inkrementieren: ObjPtr(obj)
und ObjFromPtr(ptr)
.
Das OnClipboardChange-Label wird nicht mehr automatisch aufgerufen, wenn es vorhanden ist. Verwenden Sie stattdessen die OnClipboardChange-Funktion, die es seit v1.1.20 gibt. Sie benötigt nun ein Funktionsobjekt, keinen Namen.
OnError benötigt nun ein Funktionsobjekt, keinen Namen. Siehe auch Fehlerbehandlung weiter unten.
Der OnExit-Befehl wurde entfernt; verwenden Sie stattdessen die OnExit-Funktion, die es seit v1.1.20 gibt. Sie benötigt nun ein Funktionsobjekt, keinen Namen. A_ExitReason wurde ebenfalls entfernt; der entsprechende Wert kann nun über einen Parameter der OnExit-Rückruffunktion abgerufen werden.
OnMessage hat nicht mehr den Eine-Funktion-pro-Meldung-Modus, der verwendet wurde, wenn ein Funktionsname (Zeichenkette) übergeben wurde; es akzeptiert jetzt nur eine Funktion via Referenz. Verwenden Sie OnMessage(x, MeineFunk)
, wobei MeineFunk der Name einer Funktion ist (ohne Anführungszeichen), aber beachten Sie, dass das v1-Äquivalent OnMessage(x, Func("MeineFunk"))
wäre, das im Gegensatz zu OnMessage(x, "MeineFunk")
anderen Funktionen erlaubt, die Meldung x weiter zu überwachen. Um die Überwachung der Meldung zu beenden, verwenden Sie OnMessage(x, MeineFunk, 0)
, da OnMessage(x, "")
und OnMessage(x)
nun Fehler sind. Bei Misserfolg wird OnMessage eine Ausnahme auslösen.
Pause wird nicht länger von #MaxThreadsPerHotkey ausgeschlossen, wenn es in der ersten Zeile eines Hotkeys verwendet wird, folglich ist #p::Pause
nicht mehr zum Umschalten von Pause geeignet. Pause()
pausiert nun nur den aktuellen Thread (für Kombinationen wie ListVars/Pause), während Pause(Wert)
nun immer den darunter liegenden Thread als pausiert markiert. Wert muss 0, 1 oder -1 sein. Der zweite Parameter wurde entfernt.
PixelSearch und PixelGetColor verwenden RGB- statt BGR-Werte, um mit anderen Funktionen konsistent zu sein. Beide Funktionen lösen eine Ausnahme aus, wenn ein Problem auftritt, und setzen keinen ErrorLevel mehr. PixelSearch gibt 1 (true) zurück, wenn die Farbe gefunden wurde. Der langsame Modus von PixelSearch wurde entfernt, da er auf den meisten modernen Systemen wegen Inkompatibilität mit der Desktopgestaltung unbrauchbar ist.
PostMessage: Siehe SendMessage weiter unten.
Random wurde überarbeitet, um den Zufallszahlengenerator des Betriebssystems zu nutzen, einige Einschränkungen zu beseitigen und die Verwendung zu vereinfachen.
Random(9)
eine Zahl im Bereich von 0 bis 9 zurück.Die RegExMatch-Optionen O und P wurden entfernt; der O-Modus (Objekt) ist nun immer aktiv. Das RegExMatch-Objekt unterstützt nun Enumeration (For-Schleife). Die Syntax des Match-Objekts hat sich geändert:
Match.TeilMust
zu implementieren, wobei TeilMust der Name eines Teilsuchmusters (erfassten Gruppe) ist. Da __Get nicht mehr aufgerufen wird, wenn eine Eigenschaft geerbt wird, können die folgenden Teilsuchmusternamen nicht mehr mit der Kurzform verwendet werden: Pos, Len, Name, Count, Mark. (Zum Beispiel gibt Match.Len
immer die Länge der gesamten Übereinstimmung zurück, nicht eine erfasste Zeichenkette.)Match.Name
standardmäßig eine Funktion zurückgibt, wurden die Methoden mit Eigenschaften ersetzt oder ergänzt:
Match.Name
löst einen Fehler aus).Match.0
oder Match[]
statt Match.Value()
, und Match[N]
statt Match.Value(N)
.RegisterCallback wurde in CallbackCreate umbenannt und zugunsten von Closures verbessert:
&
-Option hinzugefügt (Adresse der Parameterliste übergeben).CallbackFree(Adresse)
wurde hinzugefügt, um den Rückrufspeicher und das zugehörige Funktionsobjekt freizugeben.Registry-Funktionen (RegRead, RegWrite, RegDelete): Die in v1.1.21 eingeführte Syntax ist nun die einzige Syntax. RootSchlüssel und UnterSchlüssel wurden zusammengefasst. Schreiben Sie RootSchlüssel\UnterSchlüssel
statt RootSchlüssel, UnterSchlüssel
. Für den Zugriff auf eine Remote-Registry muss \\ComputerName\RootSchlüssel\UnterSchlüssel
statt \\ComputerName:RootSchlüssel, UnterSchlüssel
verwendet werden.
Die Parameter von RegWrite wurden neu angeordnet, so dass Wert der erste Parameter ist, wie bei IniWrite (dies hat aber keinen Einfluss auf den Einzelparametermodus, wo Wert der einzige Parameter war).
Wenn SchlüsselName weggelassen wird und das aktuelle Loop-Reg-Element ein Unterschlüssel ist, arbeiten RegDelete, RegRead und RegWrite nun mit den Werten innerhalb dieses Unterschlüssels, d.h. SchlüsselName ist in diesem Fall standardmäßig A_LoopRegKey "\" A_LoopRegName
(beachten Sie, dass A_LoopRegKey mit A_LoopRegSubKey zusammengeführt wurde). Früher verhielten sie sich wie folgt:
RegDelete, RegRead und RegWrite erlauben nun die Angabe von WertName, wenn SchlüsselName weggelassen wird:
Andernfalls löscht RegDelete mit leerem oder weggelassenem WertName nun den Standardwert des Schlüssels (nicht den Schlüssel selbst), um mit RegWrite, RegRead und A_LoopRegName konsistent zu sein. Das Schlüsselwort "AHK_DEFAULT" hat keine besondere Bedeutung mehr. Mit RegDeleteKey (neu) kann ein Schlüssel gelöscht werden.
RegRead hat jetzt wie IniRead einen Standardwert-Parameter.
RegRead hatte einen undokumentierten 5-Parameter-Modus, bei dem der Werttyp nach der Ausgabevariable angegeben werden konnte. Dieser wurde entfernt.
Reload macht nun nichts mehr, wenn das Skript aus der Standardeingabe (stdin) gelesen wurde.
Run und RunWait ignorieren nun die UseErrorLevel-Option, da ErrorLevel entfernt wurde. Verwenden Sie stattdessen Try/Catch. A_LastError wird bedingungslos gesetzt und kann nach dem Abfangen/Unterdrücken einer Ausnahme inspiziert werden. RunWait gibt den Exitcode zurück.
Send (und seine Varianten) interpretieren jetzt {LButton}
und {RButton}
konsistent zu Hotkeys und Click. Das heißt, dass LButton die primäre Taste und RButton die sekundäre Taste ist, auch dann, wenn der Benutzer die Maustasten über die Systemsteuerung vertauscht hat.
SendMessage und PostMessage: Die wParam- und lParam-Parameter müssen nun Integer oder Objekte mit einer Ptr-Eigenschaft sein; es wird eine Ausnahme ausgelöst, wenn ihnen eine nicht-numerische Zeichenkette oder Floating-Point-Zahl zugewiesen wird. Früher wurde eine Zeichenkette via Adresse übergeben, wenn der Ausdruck mit "
begann, aber andere Zeichenketten wurden zwangsweise in Integer umgewandelt. Die Übergabe der Adresse einer Variable (früher &var
, jetzt StrPtr(var)
) aktualisiert nicht mehr die Länge der Variable (verwenden Sie stattdessen VarSetStrCapacity(&var, -1)
).
SendMessage und PostMessage lösen jetzt bei Misserfolg (oder Zeitüberschreitung) eine Ausnahme aus und setzen keinen ErrorLevel mehr. SendMessage gibt die Antwort der Meldung zurück.
SetTimer unterstützt keine Label- oder Funktionsnamen mehr, aber da es jetzt einen Ausdruck akzeptiert und Funktionen direkt über ihren Namen referenziert werden können, ist die Verwendung sehr ähnlich: SetTimer MeineFunk
. Wie bei allen Funktionen, die ein Objekt akzeptieren, erlaubt SetTimer nun die Angabe von Ausdrücken, die ein Objekt zurückgeben (früher war eine Variablenreferenz erforderlich).
Sort wurde wie folgt geändert:
Ausgabe := Sort(Eingabe [, Optionen, Rückruf])
.C
-Option akzeptiert jetzt auch ein Suffix äquivalent zum GroßKleinSensitiv-Parameter anderer Funktionen (zusätzlich zu CL
): CLocale CLogical COn C1 COff C0
. Die wichtigste Neuerung ist die Unterstützung des "logischen" Vergleichsmodus.Sound-Funktionen: SoundGet und SoundSet wurden überarbeitet, um sie besser an die Sound-APIs von Windows Vista und höher anzupassen, auf Kosten der XP-Unterstützung.
StrGet: Wenn Länge negativ ist, bestimmt dessen Absolutwert die genaue Anzahl der Zeichen, die umgewandelt werden, einschließlich aller binären Nullen, die die Zeichenkette eventuell enthält, d.h. das Ergebnis wird immer eine Zeichenkette mit exakt dieser Länge sein. Wenn Länge positiv ist, endet die umgewandelte Zeichenkette bei der ersten binären Null (wie in v1).
StrGet/StrPut: Der Adresse-Parameter kann ein Objekt mit den Eigenschaften Ptr und Size sein, wie z.B. das neue Buffer-Objekt. Das Lesen/Schreiben wird automatisch via Size begrenzt (in Bytes). Wenn auch Length angegeben ist, darf es nicht größer als Size (multipliziert mit 2 bei UTF-16) sein.
Der Rückgabewert von StrPut ist nun in Bytes, so dass er direkt an Buffer()
übergeben werden kann.
StrReplace hat jetzt einen GroßKleinSensitiv-Parameter anstelle von AusgabeVarAnzahl, der um einen Parameter nach rechts verschoben wurde, mit Limit dahinter.
Suspend: Ein Hotkey oder Hotstring, der in seiner ersten Zeile Suspend aufruft, ist nicht länger vor einer Suspension geschützt. Verwenden Sie stattdessen #SuspendExempt
oder die S
-Option. Der Parameterwert "Permit" ist nicht mehr gültig.
Switch vergleicht Zeichenketten nun standardmäßig Groß-/Kleinschreibung-sensitiv und hat einen GroßKleinSensitiv-Parameter, der den Modus der Groß-/Kleinschreibung-Sensitivität überschreibt und einen Zeichenkettenvergleich (anstelle eines numerischen Vergleichs) erzwingt. Früher war der Vergleich nur Groß-/Kleinschreibung-sensitiv, wenn StringCaseSense eingeschaltet war.
SysGet hat jetzt nur noch numerische Unterbefehle; alle anderen Unterbefehle sind nun separate Funktionen. Einzelheiten finden Sie unter Unterbefehle weiter unten.
TrayTip: Die Verwendung ist nun TrayTip [Text, Titel, Optionen]
. Optionen ist eine Zeichenkette von beliebig vielen Optionen (nicht Groß-/Kleinschreibung-sensitiv), jeweils getrennt durch ein Leer- oder Tabulatorzeichen. Die Optionen sind Iconx
, Icon!
, Iconi
, Mute
und/oder ein numerischer Wert wie früher. TrayTip wird jetzt auch angezeigt, wenn Text weggelassen wird (was nun im Gegensatz zu v1 seltener versehentlich passieren kann). Der Zeitlimit-Parameter existiert nicht mehr (er funktionierte ohnehin nicht in Windows Vista oder höher). Skripte können nun die Flags NIIF_USER (0x4) und NIIF_LARGE_ICON (0x20) kombiniert verwenden (0x24), um die große Version des Tray-Symbols in der Benachrichtigung anzuzeigen. NIIF_USER (0x4) kann auch allein für das kleine Symbol verwendet werden, was aber je nach System variieren kann.
#Warn UseUnsetLocal und UseUnsetGlobal wurden entfernt, da das Lesen einer ungesetzten Variable nun einen Fehler auslöst. IsSet kann verwendet werden, um den Fehler zu vermeiden, und Try/Catch oder OnError können verwendet werden, um den Fehler zu behandeln.
#Warn VarUnset wurde hinzugefügt und verwendet standardmäßig den MsgBox-Modus. Sofern nicht deaktiviert, wird vor Beginn der Skriptausführung eine Warnung angezeigt, wenn die jeweils erste Referenz zu einer Variable nie als Ziel einer direkten nicht-dynamischen Zuweisung verwendet wird, nie mit dem Referenzoperator (&) verwendet wird oder nie direkt an IsSet übergeben wird.
#Warn Unreachable behandelt Zeilen nach einem Exit-Aufruf nicht mehr als unerreichbar, da Exit jetzt eine normale Funktion ist.
#Warn ClassOverwrite wurde entfernt, da Top-Level-Klassen nicht mehr durch Zuweisung überschrieben werden können. (Allerdings können sie nun implizit von einer lokalen Variable "überschrieben" werden; dies kann mit #Warn LocalSameAsGlobal erkannt werden.)
WinActivate sendet nun {Alt up}
nach dem ersten gescheiterten Versuch, ein Fenster zu aktivieren. Tests haben gezeigt, dass dadurch die Chance verringert wird, dass die Taskleistenschaltflächen aufblinken. Weitere Einzelheiten finden Sie in der Dokumentation.
WinClose und WinKill: Die Angabe von 0 für Wartezeit entspricht nicht länger der Angabe von 0.5; stattdessen wird die kleinstmögliche Wartezeit erzeugt.
WinSetTitle und WinMove haben nun eine Parameterreihenfolge, die mit anderen Win-Funktionen konsistent ist, d.h. FensterTitel, FensterText, AusnahmeTitel, AusnahmeText werden immer zusammen in dieser Reihenfolge verwendet (am Ende der Parameterliste), um das Einprägen der Parameter zu fördern.
Der FensterTitel-Parameter der meisten Funktionen akzeptiert nun eine HWND-Nummer (muss ein reiner Integer sein) oder ein Objekt mit einer Hwnd-Eigenschaft wie z.B. ein Gui-Objekt. DetectHiddenWindows wird in solchen Fällen ignoriert, außer bei Verwendung mit WinWait oder WinWaitClose.
WinMove hat keine spezielle Behandlung mehr für das Wort DEFAULT
. Lassen Sie den Parameter stattdessen weg oder geben Sie eine leere Zeichenkette an (funktioniert sowohl in v1 als auch in v2).
WinWait, WinWaitClose, WinWaitActive und WinWaitNotActive geben einen Wert ungleich Null zurück, wenn sie aufgehört haben zu warten (das Zeitlimit nicht überschritten wurde). ErrorLevel wurde entfernt. WinWait und WinWaitActive geben die HWND-Nummer des gefundenen Fensters zurück. WinWaitClose setzt nun das Zuletzt Gefundene Fenster, d.h. bei Zeitüberschreitung gibt WinWaitClose 0 (false) und WinExist()
das von WinWaitClose gefundene Fenster zurück. Die Angabe von 0 für Zeitlimit entspricht nicht länger der Angabe von 0.5; stattdessen wird die kleinstmögliche Wartezeit erzeugt.
Unsortiert:
Eine negative StartPos bei InStr, SubStr, RegExMatch und RegExReplace wird als Position ausgehend vom Ende interpretiert. Position -1 ist das letzte Zeichen und Position 0 ist ungültig (während in v1 Position 0 das letzte Zeichen war).
Funktionen, die früher On/Off oder On/Off/Toggle (aber keine anderen Zeichenketten) akzeptierten, benötigen nun stattdessen 1/0/-1. On und Off werden typischerweise mit True
bzw. False
ersetzt. Variablen, die On/Off zurückgegeben haben, geben jetzt 1/0 zurück, was in Ausdrücken nützlicher ist.
1
, 0
, True
und False
. (Im Gegensatz zu den anderen unterstützen sie keine Ausdrücke.)1
, 0
und -1
.Die folgenden Funktionen geben einen reinen Integer anstelle einer hexadezimalen Zeichenkette zurück:
A_ScriptHwnd gibt ebenfalls einen reinen Integer zurück.
Wenn ein Typ-Parameter eine Variable ist, wird immer der Inhalt dieser Variable verwendet, niemals ihr Name. Mit anderen Worten, anführungszeichenlose Typnamen werden nicht mehr unterstützt - die Typnamen müssen in Anführungszeichen gesetzt werden.
Wenn DllCall die Länge einer Zeichenkette aktualisiert, die als Str oder WStr übergeben wurde, erkennt DllCall nun, wenn die Zeichenkette nicht korrekt nullterminiert wurde (was wahrscheinlich auf einen Pufferüberlauf schließen lässt), und terminiert in diesem Fall das Programm mit einer Fehlermeldung, da eine sichere Ausführung nicht mehr garantiert werden kann.
AStr
(ohne irgendein Suffix) darf nur noch für Eingabeparameter verwendet werden. Da der Puffer immer nur so groß sein kann wie die Eingabezeichenkette, war AStr für Ausgabeparameter meist nicht sinnvoll. Dies würde für WStr statt AStr gelten, wenn AutoHotkey für ANSI kompiliert ist, aber offizielle v2-Versionen werden immer nur für Unicode kompiliert.
Wenn eine Funktion eine neue Adresse in einen Str*
-, AStr*
- oder WStr*
-Parameter schreibt, wird DllCall nun die neue Zeichenkette der entsprechenden Variable zuweisen, falls eine bereitgestellt wurde, anstatt nur die Länge der ursprünglichen Zeichenkette zu aktualisieren (die sich wahrscheinlich nicht geändert hat). Parameter dieses Typs werden normalerweise nicht verwendet, um die Eingabezeichenkette zu ändern, sondern um eine Zeichenkette an eine neue Adresse zurückzugeben.
DllCall akzeptiert nun ein Objekt für jeden Ptr
-Parameter und den Funktion-Parameter; das Objekt muss eine Ptr-Eigenschaft haben. Zum Reservieren von Pufferspeicher ist das neue Buffer-Objekt einer Variable vorzuziehen. Im Falle von Ptr*
wird der neue Wert des Parameters wieder der Ptr-Eigenschaft des Objekts zugewiesen. Dies ermöglicht Konstrukte wie DllCall(..., "Ptr*", unk := IUnknown())
statt DllCall(..., "Ptr*", punk), unk := IUnknown(punk)
, und kann verwendet werden, um sicherzustellen, dass jede Ausgabe der Funktion ordnungsgemäß freigegeben wird (selbst wenn eine Ausnahme aufgrund des Rückgabetyps HRESULT
ausgelöst wird, obwohl die Funktion in diesem Fall normalerweise keinen Nicht-Null-Pointer ausgeben würde).
DllCall verlangt nun, dass die Werte von Parametern numerischen Typs numerisch sein müssen, und löst eine Ausnahme aus, wenn eine nicht-numerische oder leere Zeichenkette übergeben wurde. Insbesondere wenn das Suffix * oder P für Ausgabeparameter verwendet wird, dann muss die Ausgabevariable initialisiert werden.
Der Ausgabewert (falls vorhanden) von numerischen Parametern mit dem Suffix * oder P wird ignoriert, wenn das Skript eine einfache Variable übergibt, die eine Zahl enthält. Um den Ausgabewert zu erhalten, übergeben Sie eine VarRef wie &meineVar
oder ein Objekt mit einer Ptr-Eigenschaft.
Der neue Rückgabetyp HRESULT
löst eine Ausnahme aus, wenn die Funktion fehlschlägt (int < 0
oder uint & 0x80000000
). Dies sollte nur bei Funktionen verwendet werden, die tatsächlich ein HRESULT
zurückgeben.
Das Unterbefehlschlüsselwort muss direkt geschrieben werden; es darf weder in Anführungszeichen stehen noch eine Variable oder ein Ausdruck sein. Alle anderen Parameter sind Ausdrücke. Alle Loop-Unterbefehle unterstützen nun OTB.
Entfernt:
Loop, DateiMuster [, OrdnerEinbeziehen, Rekursiv] Loop, RootSchlüssel [, Schlüssel, UnterschlüsselEinbeziehen, Rekursiv]
Verwenden Sie stattdessen folgendes (verfügbar seit v1.1.21):
Loop Files, DateiMuster [, Modus] Loop Reg SchlüsselName [, Modus]
Das Komma nach dem zweiten Wort ist jetzt optional.
A_LoopRegKey enthält nun den Root-Schlüssel und Unterschlüssel, außerdem wurde A_LoopRegSubKey entfernt.
InputBoxObj := InputBox([Anzeigetext, Titel, Optionen, Standardwert])
Der Optionen-Parameter akzeptiert eine Zeichenkette von beliebig vielen Optionen (nicht Groß-/Kleinschreibung-sensitiv), jeweils getrennt durch ein Leer- oder Tabulatorzeichen, ähnlich den Gui-Steuerelement-Optionen. Das folgende Beispiel enthält alle unterstützten Optionen: "x0 y0 w100 h100 T10.0 Password*"
. T
ist Timeout (Zeitlimit); Password
wird genauso verwendet wie die äquivalente Edit-Steuerelement-Option.
Die Optionen für Breite und Höhe bestimmen nun die Größe des Clientbereichs (das ist der Bereich ohne Titelleiste und Fensterrahmen), folglich sind sie weniger vom Design abhängig.
Der Titel ist leer, wenn der Titel-Parameter eine leere Zeichenkette ist. Der Titel ist standardmäßig nur A_ScriptName, wenn der Parameter komplett weggelassen wird, konsistent mit optionalen Parametern von benutzerdefinierten Funktionen.
InputBoxObj ist ein Objekt mit den Eigenschaften Result (enthält "OK", "Cancel" oder "Timeout") und Value.
Ergebnis := MsgBox([Text, Titel, Optionen])
Der Optionen-Parameter akzeptiert eine Zeichenkette von beliebig vielen Optionen (nicht Groß-/Kleinschreibung-sensitiv), jeweils getrennt durch ein Leer- oder Tabulatorzeichen, ähnlich den Gui-Steuerelement-Optionen.
Iconx
, Icon?
, Icon!
und Iconi
setzen das Symbol.Default
gefolgt von einem Integer macht die n-te Schaltfläche zur Standardschaltfläche.T
gefolgt von einem Integer oder einer Floating-Point-Zahl setzt den Timeout in Sekunden.Owner
gefolgt von einer HWND-Nummer setzt das übergeordnete Fenster und überschreibt die +OwnDialogs
-Gui-Option.OK
, OKCancel
, AbortRetryIgnore
, YesNoCancel
, YesNo
, RetryCancel
, CancelTryAgainContinue
, oder einfach die Initialen, mit oder ohne Schrägstriche (z.B. o/c
oder yn
).Der Rückgabewert ist der englische Name der Schaltfläche ohne Leerzeichen. Diese Zeichenketten sind dieselben, die bei IfMsgBox in v1 verwendet wurden.
Der Titel ist leer, wenn der Titel-Parameter eine leere Zeichenkette ist. Der Titel ist standardmäßig nur A_ScriptName, wenn der Parameter komplett weggelassen wird, konsistent mit optionalen Parametern von benutzerdefinierten Funktionen.
Die Unterbefehle von Control, ControlGet, Drive, DriveGet, WinGet, WinSet und Process wurden durch einzelne Funktionen ersetzt, und die Hauptbefehle wurden entfernt. Die Namen und die Verwendung einiger Funktionen wurden geändert. Diese Funktionen werden nun wie folgt verwendet:
; Die "..." sind die optionalen Parameter Steuerelement, FensterTitel, etc. Bool := ControlGetChecked(...) Bool := ControlGetEnabled(...) Bool := ControlGetVisible(...) Int := ControlGetIndex(...) ; Für Tab, LB, CB, DDL Zkette := ControlGetChoice(...) Arr := ControlGetItems(...) Int := ControlGetStyle(...) Int := ControlGetExStyle(...) Int := ControlGetHwnd(...) ControlSetChecked(TrueFalseToggle, ...) ControlSetEnabled(TrueFalseToggle, ...) ControlShow(...) ControlHide(...) ControlSetStyle(Wert, ...) ControlSetExStyle(Wert, ...) ControlShowDropDown(...) ControlHideDropDown(...) ControlChooseIndex(Index, ...) ; Deckt auch Tab ab Index := ControlChooseString(Zkette, ...) Index := ControlFindItem(Zkette, ...) Index := ControlAddItem(Zkette, ...) ControlDeleteItem(Index, ...) Int := EditGetLineCount(...) Int := EditGetCurrentLine(...) Int := EditGetCurrentCol(...) Zkette := EditGetLine(N [, ...]) Zkette := EditGetSelectedText(...) EditPaste(Zkette, ...) Zkette := ListViewGetContent([Optionen, ...]) DriveEject([Laufw]) DriveRetract([Laufw]) DriveLock(Laufw) DriveUnlock(Laufw) DriveSetLabel(Laufw [, Label]) Zkette := DriveGetList([Typ]) Zkette := DriveGetFilesystem(Laufw) Zkette := DriveGetLabel(Laufw) Zkette := DriveGetSerial(Laufw) Zkette := DriveGetType(Pfad) Zkette := DriveGetStatus(Pfad) Zkette := DriveGetStatusCD(Laufw) Int := DriveGetCapacity(Pfad) Int := DriveGetSpaceFree(Pfad) ; Die "..." sind die optionalen Parameter FensterTitel, etc. Int := WinGetID(...) Int := WinGetIDLast(...) Int := WinGetPID(...) Zkette := WinGetProcessName(...) Zkette := WinGetProcessPath(...) Int := WinGetCount(...) Arr := WinGetList(...) Int := WinGetMinMax(...) Arr := WinGetControls(...) Arr := WinGetControlsHwnd(...) Int := WinGetTransparent(...) Zkette := WinGetTransColor(...) Int := WinGetStyle(...) Int := WinGetExStyle(...) WinSetTransparent(N [, ...]) WinSetTransColor("Farbe [N]" [, ...]), WinSetAlwaysOnTop([TrueFalseToggle := 1, ...]) WinSetStyle(Wert [, ...]) WinSetExStyle(Wert [, ...]) WinSetEnabled(Wert [, ...]) WinSetRegion(Wert [, ...]) WinRedraw(...) WinMoveBottom(...) WinMoveTop(...) PID := ProcessExist([PID_oder_Name]) PID := ProcessClose(PID_oder_Name) PID := ProcessWait(PID_oder_Name [, Timeout]) PID := ProcessWaitClose(PID_oder_Name [, Timeout]) ProcessSetPriority(Priority [, PID_oder_Name])
ProcessExist, ProcessClose, ProcessWait und ProcessWaitClose setzen keinen ErrorLevel mehr; sie geben stattdessen die PID zurück.
Keine der anderen Funktionen setzt ErrorLevel. Stattdessen lösen sie bei Misserfolg eine Ausnahme aus. In den meisten Fällen ist ein Misserfolg darauf zurückzuführen, dass das Zielfenster oder -steuerelement nicht gefunden wurde.
HWND-Nummern und Styles werden immer als reine Integer zurückgegeben, nicht als hexadezimale Zeichenketten.
ControlChooseIndex akzeptiert 0, um alle Elemente abzuwählen. Es ersetzt "Control Choose", unterstützt aber auch Tab-Steuerelemente.
"ControlGet Tab" wurde mit ControlGetIndex zusammengeführt, das auch mit ListBox, ComboBox und DDL funktioniert. Bei Tab-Steuerelementen gibt es 0 zurück, wenn kein Tab ausgewählt ist (selten, aber möglich). ControlChooseIndex erlaubt keine 0 für Tab-Steuerelemente, da Anwendungen in der Regel nicht damit umgehen können.
ControlGetItems ersetzt "ControlGet List" für ListBox und ComboBox. Es gibt ein Array zurück.
DriveEject und DriveRetract verwenden jetzt DeviceIoControl anstelle von mciSendString. DriveEject kann dadurch Nicht-CD/DVD-Laufwerke auswerfen, die eine "Auswerfen"-Option im Explorer haben (d.h. Wechseldatenträger, aber keine externen Festplatten).
ListViewGetContent ersetzt "ControlGet List" für ListView und wird aktuell genauso verwendet wie früher.
WinGetList, WinGetControls und WinGetControlsHwnd geben Arrays zurück, keine zeilenumbruchgetrennte Liste.
WinSetTransparent behandelt ""
als "Off"
und nicht als 0
(was das Fenster unsichtbar und unklickbar machen würde).
Abkürzungen wie Topmost, Trans, FS und Cap wurden entfernt.
Die folgenden Funktionen waren früher Unterbefehle von SysGet:
AktuelleN := MonitorGet([N, &Links, &Oben, &Rechts, &Unten]) AktuelleN := MonitorGetWorkArea([N, &Links, &Oben, &Rechts, &Unten]) Anzahl := MonitorGetCount() Primär := MonitorGetPrimary() Name := MonitorGetName([N])
Buffer([ByteAnzahl, FüllByte])
(Aufruf der Buffer-Klasse) erzeugt und gibt ein Buffer
-Objekt zurück, das einen Bereich im Speicher mit einer Größe von ByteAnzahl Bytes beansprucht, der nur initialisiert ist, wenn FüllByte angegeben ist. BufferObj.Ptr
gibt die Adresse zurück. BufferObj.Size
gibt die Größe in Bytes zurück oder setzt sie (und reserviert den Bereich des Speichers neu). Es kann ein beliebiges Objekt mit einer Ptr- und Size-Eigenschaft an NumPut, NumGet, StrPut, StrGet, File.RawRead, File.RawWrite und FileAppend übergeben werden. Es kann ein beliebiges Objekt mit einer Ptr-Eigenschaft an DllCall-Parametern vom Typ Ptr
, SendMessage und PostMessage übergeben werden.
CaretGetPos([&OutputVarX, &OutputVarY])
ruft die aktuellen Koordinaten des Textcursors (Texteinfügemarke) ab. Dies stellt sicher, dass die X- und Y-Koordinate immer übereinstimmen und dass es kein Caching gibt, das zu unerwartetem Verhalten führt (z.B. wenn A_CaretX/Y einen Wert zurückgibt, der nicht im aktuellen Koordinatenmodus ist).
ClipboardAll([Daten, Größe])
erstellt ein Objekt mit allem, was in der Zwischenablage enthalten ist (und akzeptiert optional Daten, die vorher aus der Zwischenablage abgerufen wurden, anstatt den aktuellen Inhalt der Zwischenablage zu verwenden). Die Methoden zum Lesen und Schreiben von Zwischenablagedateidaten sind unterschiedlich. Das Datenformat ist das gleiche, außer dass die Datengröße immer 32-Bit ist, so dass die Daten zwischen 32-Bit- und 64-Bit-Builds portierbar sind. Einzelheiten finden Sie in der v2-Dokumentation.
ComCall(offset, comobj, ...)
ist äquivalent zu DllCall(NumGet(NumGet(comobj.ptr) + offset * A_Index), "ptr", comobj.ptr, ...)
, aber standardmäßig mit dem Rückgabetyp HRESULT
anstelle von Int
.
ComObject (ehemals ComObjCreate) und ComObjQuery geben jetzt ein Wrapper-Objekt zurück, auch dann, wenn eine IID angegeben ist. ComObjQuery erlaubt für den ersten Parameter ein beliebiges Objekt mit einer Ptr-Eigenschaft.
ControlGetClassNN gibt die ClassNN-Bezeichnung eines bestimmten Steuerelements zurück.
ControlSendText, das äquivalent zu ControlSendRaw ist, aber den Text- statt Raw-Modus verwendet.
DirExist(DateiMuster)
, das so ähnlich wie FileExist verwendet wird. Beachten Sie, dass eine Platzhalterprüfung wie InStr(FileExist("MeinOrdner\*"), "D")
, wobei MeinOrdner Dateien und Unterordner enthält, nur mitteilt, ob die erste gefundene Datei ein Ordner ist, nicht ob ein Ordner existiert.
Float(Wert)
: Siehe Typen weiter oben.
InstallKeybdHook([Installieren, Erzwingen])
und InstallMouseHook([Installieren, Erzwingen])
ersetzen die entsprechenden Direktiven, für erhöhte Flexibilität.
Integer(Wert)
: Siehe Typen weiter oben.
IsXXX: Der Legacy-Befehl "if Var is Typ" wurde durch mehrere Funktionen ersetzt: IsAlnum, IsAlpha, IsDigit, IsFloat, IsInteger, IsLower, IsNumber, IsSpace, IsUpper, IsXDigit. Außer IsFloat, IsInteger und IsNumber lösen alle eine Ausnahme aus, wenn der Parameter keine Zeichenkette ist, da eine implizite Umwandlung in eine Zeichenkette zu kontraproduktiven Ergebnissen führen kann.
IsSet(Var)
, IsSetRef(&Ref)
: Gibt 1 (true) zurück, wenn der Variable ein Wert zugewiesen wurde (auch wenn dieser Wert eine leere Zeichenkette ist), andernfalls 0 (false). Bei 0 (false) würde der Versuch, die Variable innerhalb eines Ausdrucks zu lesen, einen Fehler auslösen.
Menu()
/MenuBar()
gibt ein neues Menu/MenuBar-Objekt zurück, das die folgenden Elemente analog zu den v1-Menu-Unterbefehlen enthält. Methoden: Add, AddStandard, Check, Delete, Disable, Enable, Insert, Rename, SetColor, SetIcon, Show, ToggleCheck, ToggleEnable, Uncheck. Eigenschaften: ClickCount, Default, Handle (ersetzt MenuGetHandle). A_TrayMenu gibt ebenfalls ein Menu-Objekt zurück. Es gibt keinen UseErrorLevel-Modus, keine globalen Menünamen, und kein explizites Löschen des Menüs selbst (dies geschieht, wenn alle Referenzen freigegeben werden; die Delete-Methode ist äquivalent zu DeleteAll von v1). Labels werden nicht unterstützt, nur Funktionsobjekte. Die AddStandard-Methode fügt die vordefinierten Menüpunkte hinzu und ermöglicht es, diese wie benutzerdefinierte Menüpunkte individuell zu ändern. Im Gegensatz zu v1 wird das Win32-Menü nur zerstört, wenn das Objekt gelöscht wird.
MenuFromHandle(Handle)
ruft ein Menu- oder MenuBar-Objekt über dessen Win32-Menü-Handle ab, wenn es von AutoHotkey erstellt wurde.
Number(Wert)
: Siehe Typen weiter oben.
Persistent([Persistieren])
ersetzt die entsprechende Direktive, was die Flexibilität erhöht.
RegDeleteKey([SchlüsselName])
löscht einen Registry-Schlüssel. (RegDelete löscht jetzt nur noch Werte, außer wenn alle Parameter in einer Registry-Schleife weggelassen werden.)
SendText, das äquivalent zu SendRaw ist, aber den Text- statt Raw-Modus verwendet.
StrCompare(Zkette1, Zkette2 [, GroßKleinSensitiv])
gibt -1 (Zkette1 kleiner als Zkette2), 0 (gleich) oder 1 (größer als) zurück. GroßKleinSensitiv kann "Locale" sein.
String(Wert)
: Siehe Typen weiter oben.
StrPtr(Wert)
gibt die Adresse einer Zeichenkette zurück. Im Gegensatz zum Adressoperator von v1 kann dies mit direkt geschriebenen Zeichenketten und temporären Zeichenketten verwendet werden.
SysGetIPAddresses()
gibt ein Array von IP-Adressen zurück, äquivalent zu den entfernten A_IPAddress-Variablen. Jede Referenz zu A_IPAddress%N%
rief alle Adressen ab, gab aber nur eine zurück, so dass das Abrufen mehrerer Adressen exponentiell länger dauerte als nötig. Das zurückgegebene Array kann beliebig viele Elemente enthalten.
TraySetIcon([DateiName, SymbolNummer, Einfrieren])
ersetzt "Menu Tray, Icon".
VarSetStrCapacity(&ZielVar [, GewünschteKapazität])
ersetzt die v1-Funktion VarSetCapacity, ist aber nur für die Verwendung mit UTF-16-Zeichenketten vorgesehen (z.B. um Mehrfachverkettungen zu optimieren); folglich sind GewünschteKapazität und der Rückgabewert in Zeichen, nicht in Bytes.
VerCompare(A, B)
vergleicht zwei Versionszeichenketten mit dem gleichen Algorithmus wie #Requires.
WinGetClientPos([&AusX, &AusY, &AusBreite, &AusHöhe, FensterTitel, ...])
ruft die Position und Größe des Clientbereichs eines Fensters ab, in Bildschirmkoordinaten.
#DllLoad [DateiOderVerzName]
: Lädt eine DLL- oder EXE-Datei vor Beginn der Skriptausführung.
A_AhkPath gibt immer den Pfad der aktuellen EXE-Datei oder des Interpreters zurück, auch dann, wenn das Skript kompiliert ist. Früher wurde der Pfad des kompilierten Skripts zurückgegeben, wenn eine BIN-Datei als Basisdatei verwendet wurde, aber v2.0-Releases enthalten keine BIN-Dateien mehr.
A_IsCompiled gibt 0 statt "" zurück, wenn das Skript nicht kompiliert ist.
A_OSVersion gibt immer eine Zeichenkette im Format Haupt.Neben.Build
zurück, z.B. 6.1.7601
für Windows 7 SP1. A_OSType wurde entfernt, da nur NT-basierte Systeme unterstützt wurden.
A_TimeSincePriorHotkey gibt "" statt -1 zurück, wenn A_PriorHotkey "" ist. A_TimeSinceThisHotkey gibt "" statt -1 zurück, wenn A_ThisHotkey "" ist.
Alle internen "virtuellen" Variablen haben jetzt das A_
-Präfix (Einzelheiten finden Sie unten). Alle vordefinierten Variablen ohne dieses Präfix (z.B. Object
) sind nur globale Variablen. Die Unterscheidung kann wichtig sein, da es derzeit nicht möglich ist, eine virtuelle Variable zu referenzieren (außer wenn sie direkt an eine interne Funktion übergeben wird); A_Args ist jedoch keine virtuelle Variable.
Interne Variablen, die Zahlen zurückgeben, geben diese jetzt als Integer statt als Zeichenkette zurück.
Umbenannt:
Entfernt:
StrLen(Chr(0xFFFF))
ersetzt oder mit global A_IsUnicode := 1
neu definiert werden)Hinzugefügt:
Den folgenden internen Variablen können Werte zugewiesen werden:
File-Objekte erfordern jetzt strikt die Eigenschaftssyntax für den Aufruf von Eigenschaften und die Methodensyntax für den Aufruf von Methoden. Zum Beispiel ist FileObj.Pos(n)
ungültig. Es wird eine Ausnahme ausgelöst, wenn zu wenige oder zu viele Parameter vorhanden sind oder wenn einer schreibgeschützten Eigenschaft ein Wert zugewiesen wird.
File.Tell() wurde entfernt.
Func.IsByRef() funktioniert nun mit internen Funktionen.
Gui, GuiControl und GuiControlGet wurden durch Gui() und Gui/GuiControl-Objekte ersetzt, die in der Regel flexibler, konsistenter und leichter zu bedienen sind.
Eine GUI wird typischerweise nicht via Name/Nummer referenziert (obwohl sie immer noch mit GuiObj.Name
benannt werden kann). Stattdessen wird ein GUI-Objekt (und Fenster) explizit durch Instanziierung der Gui
-Klasse erstellt, wie in GuiObj := Gui()
. Dieses Objekt hat Methoden und Eigenschaften, die die Gui-Unterbefehle ersetzen. Gui.Add() gibt ein GuiControl-Objekt zurück, das Methoden und Eigenschaften hat, die die GuiControl- und GuiControlGet-Befehle ersetzen. Dieses Objekt kann in eine Variable gespeichert oder mit GuiObj["Name"]
oder GuiCtrlFromHwnd abgerufen werden. Es wird auch als Parameter übergeben, wenn ein Ereignishandler (der g-Label-Ersatz) aufgerufen wird.
Die Verwendung dieser Methoden und Eigenschaften ist nicht 1:1. Vieles wurde überarbeitet, um konsistenter und flexibler zu sein und um Fehler oder Einschränkungen zu beheben.
Es gibt keine Standard-GUIs, da das zu verwendende Gui- oder GuiControl-Objekt immer angegeben ist. LV/TV/SB-Funktionen wurden durch Methoden (des GuiControl-Objekts) ersetzt, so dass es viel einfacher ist, mehrere ListViews/TreeViews zu verwenden.
Es gibt keine internen Variablen, die Informationen über Ereignisse enthalten. Stattdessen werden die Informationen als Parameter an die ereignisbehandelnde Funktion/Methode übergeben, einschließlich des Gui- oder GuiControl-Objekts.
Steuerelemente können weiterhin benannt und via Name referenziert werden. Dies ist jedoch nur ein Name (der mit GuiObj["Name"]
und Gui.Submit() verwendet wird), keine zugeordnete Variable, daher müssen keine globalen oder statischen Variablen deklariert oder erstellt werden. Der Wert wird nie automatisch in eine Variable gespeichert, kann aber über GuiControl.Value abgerufen oder gesetzt werden. Gui.Submit() gibt ein neues assoziatives Array zurück, das die Namen der Steuerelemente als Schlüssel verwendet.
Die vName
-Option setzt nun nur noch den Namen des Steuerelements auf Name.
Die +HwndVarName
-Option wurde zugunsten von GuiControl.Hwnd entfernt.
Es gibt keine "g-Labels" oder Labels/Funktionen mehr, die GUI-Ereignisse automatisch behandeln. Das Skript muss für jedes gewünschte Ereignis eine Rückruffunktion registrieren, indem es die OnEvent-Methode des Gui oder GuiControl aufruft. Anstatt z.B. if (A_GuiEvent = "I" && InStr(ErrorLevel, "F", true))
in einem g-Label zu prüfen, registriert das Skript einen Handler für das ItemFocus-Ereignis: MeineLV.OnEvent("ItemFocus", MeineFunktion)
. MeineFunktion würde nur für das ItemFocus-Ereignis aufgerufen werden. Die AltSubmit
-Option ist nicht mehr erforderlich, um zusätzliche Ereignisse zu erkennen.
Arrays werden überall dort verwendet, wo zuvor eine via Vertikalstrich getrennte Liste verwendet wurde, z.B. um die Listeneinträge für eine ListBox anzugeben, wenn die ListBox erstellt wird, wenn Einträge hinzugefügt werden oder wenn die ausgewählten Einträge abgerufen werden.
Skripte können eine Klasse definieren, die Gui
erweitert und ihre eigenen Ereignisse behandelt, wobei die gesamte GUI-Logik in sich geschlossen bleibt.
Gui New → Gui(). Die Übergabe einer leeren Zeichenkette bewirkt, dass nicht der Standardtitel, sondern ein leerer Titel angezeigt wird.
Gui Add → Gui.Add() oder Gui.AddSteuerelement(); z.B. GuiObj.Add("Edit")
oder GuiObj.AddEdit()
.
Gui Show → Gui.Show(), aber ohne Titel-Parameter. Der Titel kann via Parameter von Gui() oder via Gui.Title-Eigenschaft angegeben werden. Der initiale Fokus wird immer noch auf das erste eingabefähige Steuerelement mit dem WS_TABSTOP-Style gesetzt (gemäß der Standardmeldungsverarbeitung des Systems), es sei denn, es handelt sich um ein Button-Steuerelement, dann wird der Fokus jetzt auf die Standardschaltfläche verschoben.
Gui Submit → Gui.Submit(). Funktioniert wie früher, außer dass Submit() ein neues Objekt erstellt und zurückgibt, das alle "zugeordneten Variablen" enthält.
Gui Destroy → Gui.Destroy(). Das Objekt existiert weiterhin (bis es vom Skript freigegeben wird), kann aber nicht verwendet werden. Es muss eine neue GUI erstellt werden (falls erforderlich). Das Fenster wird auch zerstört, wenn das Objekt gelöscht wird, aber das Objekt wird "am Leben gehalten", solange das Fenster sichtbar ist.
Gui Font → Gui.SetFont(). Mit GuiControl.SetFont() kann auch direkt die Schriftart eines Steuerelements gesetzt werden.
Gui Color → Gui.BackColor setzt oder gibt die Hintergrundfarbe zurück. SteuerelementFarbe (der zweite Parameter) wird nicht unterstützt, aber bei allen Steuerelementen, die diesen Parameter früher unterstützt haben, kann stattdessen der Hintergrund via +Background
-Option geändert werden. Im Gegensatz zu "Gui Color" hat Gui.BackColor keinen Einfluss auf Progress-Steuerelemente oder deaktivierte/schreibgeschützte TreeView- (mit -Theme
), Edit-, DDL- oder ComboBox-Steuerelemente.
Gui Margin → die Eigenschaften Gui.MarginX und Gui.MarginY.
Gui Menu → Gui.MenuBar setzt oder gibt ein via MenuBar()
erstelltes MenuBar-Objekt zurück.
Gui Cancel/Hide/Minimize/Maximize/Restore → gleichnamige Gui-Methoden.
Gui Flash → Gui.Flash(), aber false
statt Off
verwenden.
Gui Tab → GuiControl.UseTab(). Es kann weiterhin ein Tabname angegeben werden, wobei wie früher standardmäßig der Tab verwendet wird, dessen führender Namensteil mit der angegebenen Zeichenkette übereinstimmt. Übergeben Sie True im zweiten Parameter, um zu bewirken, dass die angegebene Zeichenkette eine exakte Übereinstimmung sein muss, aber im Gegensatz zum Exakt-Modus von v1 ist die Suche nicht Groß-/Kleinschreibung-sensitiv.
Informationen darüber, welche GUI-Ereignisse und GUI-Steuerelement-Ereignisse explizit unterstützt werden, finden Sie unter Ereignisse (OnEvent).
Das Size-Ereignis übergibt 0,-1 oder 1 (konsistent mit WinGetMinMax) statt 0, 1 oder 2.
Das ContextMenu-Ereignis kann für jedes Steuerelement oder für die gesamte GUI registriert werden.
Das DropFiles-Ereignis vertauscht die Parameter DateiArray und Ctrl, um mit ContextMenu konsistent zu sein.
Die Ereignisse ContextMenu und DropFiles verwenden Clientkoordinaten statt Fensterkoordinaten (Client ist auch der standardmäßig verwendete Koordinatenmodus in v2).
Die folgenden Steuerelementereignisse wurden entfernt, können aber weiterhin durch Übergabe des entsprechenden numerischen Benachrichtigungscodes (definiert im Windows SDK) an GuiControl.OnNotify() erkannt werden: K, D, d, A, S, s, M, C, E und die MonthCal-Ereignisse 1 und 2.
Steuerelementereignisse übergeben den Ereignisnamen nicht als Parameter (GUI-Ereignisse taten dies nie).
Custom: Die Ereignisse N und Normal wurden mit GuiControl.OnNotify() und GuiControl.OnCommand() ersetzt, die für alle Steuerelemente verwendet werden können.
Link: Das Click-Ereignis übergibt "Ctrl, ID oder Index, HREF" statt "Ctrl, Index, HREF oder ID", und führt HREF nicht automatisch aus, wenn eine Click-Rückruffunktion registriert ist.
ListView: Die Ereignisse Click, DoubleClick und ContextMenu (wenn ausgelöst durch einen Rechtsklick) melden nun das angeklickte Element (andernfalls 0), nicht das fokussierte Element.
ListView: Das I-Ereignis wurde in mehrere benannte Ereignisse aufgeteilt, außer f (defokussiert), da es mit F (ItemFocus) erkannt werden kann.
ListView: Das e-Ereignis (ItemEdit) wird ignoriert, wenn der Benutzer das Editieren abbricht.
Slider: Das Change-Ereignis wird konsistenter ausgelöst als das g-Label von v1, d.h. es ignoriert nicht länger standardmäßig Änderungen durch das Mausrad. Einzelheiten finden Sie unter Erkennen von Änderungen (Slider).
Der BS_NOTIFY-Style wird jetzt bei Bedarf automatisch für Button-, CheckBox- und Radio-Steuerelemente hinzugefügt. Radio-Steuerelemente haben diesen Style standardmäßig nicht mehr.
Focus (ehemals F) und LoseFocus (ehemals f) werden von mehr (aber nicht allen) Steuerelementtypen unterstützt.
Im Gegensatz zu GuiControl, das das g-Label eines Edit-Steuerelements auslöst, wird beim Setzen des Textes eines Edit-Steuerelements mit Edit.Value oder Edit.Text das Change-Ereignis nicht ausgelöst.
LV/TV.Add/Modify unterdrücken jetzt elementverändernde Ereignisse, so dass solche Ereignisse nur durch Benutzeraktion oder SendMessage ausgelöst werden können.
+Delimiter
+HwndAusgabeVar(verwenden Sie stattdessen Gui.Hwnd oder GuiControl.Hwnd)
+Label
+LastFoundExist
Gui GuiName: Default
+/-Background wird konsistenter interpretiert und unterstützt. Alle Steuerelemente, die "Gui Color" unterstützt haben, unterstützen nun +BackgroundFarbe
und +BackgroundDefault
(synonym mit -Background
), nicht nur ListView/TreeView/StatusBar/Progress.
Gui.Add() verwendet standardmäßig y+m
/x+m
anstatt yp
/xp
, wenn xp
/yp
oder xp+0
/yp+0
verwendet wird. Mit anderen Worten, das Steuerelement wird unterhalb/rechts vom vorherigen Steuerelement platziert, anstatt auf genau derselben Position. Wenn ein Offset ungleich Null verwendet wird, ist das Verhalten das gleiche wie in v1. Um genau dieselbe Position zu verwenden, geben Sie xp yp
gemeinsam an.
Direkt nach x+m
und y+m
kann optional ein Offset angegeben werden, z.B. x+m+10
(x+m10
ist auch gültig, aber schlechter lesbar).
Choose
dient nicht länger als redundante (undokumentierte) Möglichkeit, den Wert für MonthCal anzugeben. Verwenden Sie einfach wie früher den Text-Parameter.
Der leere Unterbefehl von GuiControlGet hatte zwei Modi: Standardmodus und Textmodus. Für den Textmodus musste das Wort Text
im vierten Parameter angegeben werden. Wenn ein Steuerelement keinen "Wert" hatte, gab GuiControlGet standardmäßig das Ergebnis von GetWindowText zurück (was nicht immer sichtbarer Text ist). Einige Steuerelemente hatten keinen sichtbaren Text oder unterstützten dessen Abruf nicht, folglich ignorierten sie den vierten Parameter. GuiControl.Text gibt hingegen den Anzeigetext, versteckten Text (derselbe Text, den ControlGetText zurückgibt) oder gar nichts zurück.
Die folgende Tabelle zeigt pro Steuerelementtyp die nächstbeste Eigenschaft oder Funktion für beide GuiControlGet-Modi an.
Steuerelement | Standard | Text | Hinweise |
---|---|---|---|
ActiveX | .Value | .Text | Text ist versteckt. Siehe unten. |
Button | .Text | ||
CheckBox | .Value | .Text | |
ComboBox | .Text | ControlGetText() | Value statt Text verwenden, wenn AltSubmit verwendet wurde (aber Value gibt 0 zurück, wenn Text mit keinem Listenelement übereinstimmt). Text korrigiert die Groß-/Kleinschreibung, während ControlGetText den Inhalt des Eingabefeldes zurückgibt. |
Custom | .Text | ||
DateTime | .Value | ||
DDL | .Text | Value statt Text verwenden, wenn AltSubmit verwendet wurde. | |
Edit | .Value | ||
GroupBox | .Text | ||
Hotkey | .Value | ||
Link | .Text | ||
ListBox | .Text | ControlGetText() | Value statt Text verwenden, wenn AltSubmit verwendet wurde. Text gibt den Text des ausgewählten Eintrags zurück, während ControlGetText den versteckten Text zurückgibt. Siehe unten. |
ListView | .Text | Text ist versteckt. | |
MonthCal | .Value | ||
Picture | .Value | ||
Progress | .Value | ||
Radio | .Value | .Text | |
Slider | .Value | ||
StatusBar | .Text | ||
Tab | .Text | ControlGetText() | Value statt Text verwenden, wenn AltSubmit verwendet wurde. Text gibt den Text des ausgewählten Tabs zurück, während ControlGetText den versteckten Text zurückgibt. |
Text | .Text | ||
TreeView | .Text | Text ist versteckt. | |
UpDown | .Value |
ListBox: Bei einer Mehrfachauswahl-ListBox gibt Text und Value ein Array statt einer via Vertikalstrich getrennten Liste zurück.
ActiveX: GuiControl.Value gibt jedes Mal dasselbe Objekt zurück, während GuiControlGet jedes Mal ein neues Wrapper-Objekt erstellt. Folglich ist es nicht mehr notwendig, für eine ComObjConnect-Verbindung eine Referenz zum ActiveX-Objekt aufrechtzuerhalten.
Pos → GuiControl.GetPos()
Focus → Gui.FocusedCtrl; gibt ein GuiControl-Objekt anstelle der ClassNN-Bezeichnung zurück.
FocusV → GuiObj.FocusedCtrl.Name
Hwnd → GuiControl.Hwnd; gibt einen reinen Integer zurück, keine hexadezimale Zeichenkette.
Enabled/Visible/Name → gleichnamige GuiCtrl-Eigenschaften.
Die folgende Tabelle zeigt pro Steuerelementtyp die nächstbeste Eigenschaft oder Methode für beide GuiControl-Modi an.
Steuerelement | (Leer) | Text | Hinweise |
---|---|---|---|
ActiveX | N/A | Befehl war wirkungslos. | |
Button | .Text | ||
CheckBox | .Value | .Text | |
ComboBox | .Delete/Add/Choose | .Text | |
Custom | .Text | ||
DateTime | .Value | .SetFormat() | |
DDL | .Delete/Add/Choose | ||
Edit | .Value | ||
GroupBox | .Text | ||
Hotkey | .Value | ||
Link | .Text | ||
ListBox | .Delete/Add/Choose | ||
ListView | N/A | Befehl war wirkungslos. | |
MonthCal | .Value | ||
Picture | .Value | ||
Progress | .Value | += -Operator statt + -Präfix verwenden. | |
Radio | .Value | .Text | |
Slider | .Value | += -Operator statt + -Präfix verwenden. | |
StatusBar | .Text oder SB.SetText() | ||
Tab | .Delete/Add/Choose | ||
Text | .Text | ||
TreeView | N/A | Befehl war wirkungslos. | |
UpDown | .Value | += -Operator statt + -Präfix verwenden. |
Move → GuiControl.Move()
MoveDraw → GuiControl.Move(), GuiControl.Redraw()
Focus → GuiControl.Focus(), das nun WM_NEXTDLGCTL statt SetFocus verwendet, so dass eine Schaltfläche beim Fokussieren temporär zur Standardschaltfläche gemacht wird, was mit dem Tabben zum Steuerelement konsistent ist.
Enable/Disable → GuiControl.Enabled setzen
Hide/Show → GuiControl.Visible setzen
Choose → GuiControl.Choose(n), wobei n ein reiner Integer ist. Der |n
- oder ||n
-Modus wird nicht unterstützt (verwenden Sie stattdessen ControlChooseIndex, wenn nötig).
ChooseString → GuiControl.Choose(s), wobei s kein reiner Integer ist. Der |n
- oder ||n
-Modus wird nicht unterstützt (verwenden Sie stattdessen ControlChooseString, wenn nötig). Wenn die Zeichenkette mit mehreren Einträgen in einer Mehrfachauswahl-ListBox übereinstimmt, wird diese Methode alle gefundenen Einträge auswählen, nicht nur den ersten.
Font → GuiControl.SetFont()
+/-Option → GuiControl.Opt("+/-Option")
Progress-Gui-Steuerelemente haben nicht mehr standardmäßig den PBS_SMOOTH-Style, d.h. ihr Aussehen richtet sich jetzt nach dem aktuellen Design des Betriebssystems.
Die Standardabstände und Steuerelementgrößen (insbesondere bei Button-Steuerelementen) können leicht von v1 abweichen, wenn DPI größer als 100 % ist.
Picture-Steuerelemente löschen ihr aktuelles Bild nicht mehr, wenn das Setzen eines neuen Bildes via GuiCtrl.Value := "neues Bild.png"
fehlschlägt. Es ist jedoch erlaubt, das aktuelle Bild mit GuiCtrl.Value := ""
zu entfernen.
Der SpalteNummer-Parameter von ListView.InsertCol() kann jetzt weggelassen werden, was dasselbe bewirkt wie, als würde man eine Spaltennummer größer als die Anzahl der aktuellen Spalten im Steuerelement angeben.
OnError wird nun bei kritischen Fehlern vor Beendigung des Skripts aufgerufen. Obwohl sich das Skript möglicherweise nicht in einem Zustand befindet, der eine sichere Ausführung zulässt, wird dies versucht, konsistent mit OnExit.
Laufzeitfehler setzen Exception.What
nicht mehr auf die gerade ausgeführte benutzerdefinierte Funktion oder Subroutine (obwohl dies immer noch geschieht, wenn Error()
ohne den zweiten Parameter aufgerufen wird). Dadurch wird der Zweck von What
klarer: Ein Funktionsname weist auf einen Misserfolg dieser Funktion hin (nicht auf einen Misserfolg beim Aufruf der Funktion oder bei der Auswertung ihrer Parameter). What
ist leer bei Fehlern bzgl. Ausdrucksauswertung und Kontrollfluss (einige andere können auch leer sein).
Exception-Objekte, die durch Laufzeitfehler ausgelöst werden, können jetzt als Instanzen der neuen Error-Klasse oder einer spezifischeren Unterklasse identifiziert werden. Error-Objekte haben eine Stack-Eigenschaft, die einen Stacktrace enthält. Wenn der What-Parameter den Namen einer laufenden Funktion angibt, werden File und Line nun entsprechend der Zeile gesetzt, die diese Funktion aufgerufen hat.
Die Try-Catch-Syntax wurde geändert, damit das Skript gezielt bestimmte Error-Klassen abfangen kann. Weitere Informationen finden Sie unter Catch unten.
In den meisten Fällen bieten die Fehlerdialogfenster jetzt die Möglichkeit, den aktuellen Thread fortzusetzen (anstatt den Thread nur zu beenden). COM-Fehler beenden jetzt den Thread, wenn Sie sich gegen eine Fortsetzung entscheiden (anstatt das komplette Skript zu beenden).
Skripte sollten sich nicht darauf verlassen: Wenn der Fehler von einer internen Funktion ausgelöst wurde, wird beim Fortsetzen ein "" zurückgegeben. Wenn der Fehler vom Ausdrucksevaluator ausgelöst wurde (z.B. bei einer ungültigen dynamischen Referenz oder einer Division durch 0), wird der Ausdruck abgebrochen und "" zurückgegeben (wenn er als Parameter einer Kontrollanweisung verwendet wird).
In einigen Fällen unterstützt der Code keine Fortsetzung; in diesem Fall sollte die Fortsetzungsoption nicht angezeigt werden. Die Option wird auch nicht für kritische Fehler angezeigt, da diese für die Terminierung des Skripts konzipiert sind.
OnError-Rückruffunktionen akzeptieren jetzt einen zweiten Parameter, der einen der folgenden Werte enthält:
ErrorLevel wurde entfernt. Skripte werden häufig (oder üblicherweise) ohne Fehlerprüfung geschrieben, so dass die ErrorLevel-Setzung bei Fehlern oft unbemerkt blieb. Eine sofortige Fehlermeldung mag ein wenig konfrontativ erscheinen, ist aber in der Regel hilfreicher.
Wo früher ErrorLevel gesetzt wurde, um einen Fehlerzustand anzugeben, wird nun eine Ausnahme mit einer (normalerweise) hilfreicheren Fehlermeldung ausgelöst.
Befehle wie "Process Exist", die mit ErrorLevel einen Wert zurückgegeben haben, geben jetzt einfach diesen Wert (z.B. PID := ProcessExist()
) oder etwas Nützlicheres (z.B. HWND := GroupActivate(Gruppe)
) zurück.
In einigen Fällen wurde ErrorLevel als sekundärer Rückgabewert verwendet.
File-Funktionen, die früher die Anzahl der Misserfolge in ErrorLevel gespeichert haben, speichern diese Information nun in die Extra-Eigenschaft des ausgelösten Exception-Objekts.
SendMessage-Timeout (Zeitüberschreitung) ist in der Regel ein anomaler Zustand und bewirkt, dass ein TimeoutError ausgelöst wird. TargetError und OSError können unter anderen Bedingungen ausgelöst werden.
Der UseErrorLevel-Modus von Run und Hotkey wurde entfernt. Dieser Modus wurde eingeführt, als es noch kein Try/Catch gab. Menu und Gui hatten diesen Modus auch, wurden aber durch Objekte ersetzt (die ErrorLevel nicht verwenden).
Es wird ein Ladezeitfehler bei mehr Fehlern als in v1 ausgelöst. Zum Beispiel:
x ()
x!
Es wird eine Ausnahme ausgelöst, wenn einer der folgenden Fehler auftritt (anstatt den Fehler zu ignorieren oder eine leere Zeichenkette zu erzeugen):
(-1)**1.5
. Beachten Sie, dass einige Fälle jetzt als ungültig erkannt werden, z.B. 0**0
und a<<b
oder a>>b
, wobei b außerhalb des Bereichs 0 bis 63 liegt.fn(%leer%)
.Einige der Bedingungen oben werden in v1 erkannt, aber nicht inmitten eines Ausdrucks; zum Beispiel wird A_AhkPath := x
in v1 erkannt, während y := x, A_AhkPath := x
nur in v2 erkannt werden kann.
Bei separater Verwendung der Operatoren +=
, -=
, --
und ++
wird eine leere Variable nicht mehr als 0 behandelt. Dies unterscheidet sich von v1, wo sie bei separater Verwendung eine leere Variable als 0 behandelten, aber nicht inmitten eines Ausdrucks oder mit einem Mehrfachanweisungskomma.
Funktionen lösen bei Misserfolg grundsätzlich eine Ausnahme aus. Genauer gesagt:
Fehler durch falsche Verwendung von DllCall, RegExMatch und RegExReplace kamen aufgrund ihrer Komplexität recht häufig vor und sind (wie viele Fehler) leichter zu erkennen und zu debuggen, wenn sofort eine Fehlermeldung angezeigt wird.
Mathematische Funktionen lösen eine Ausnahme aus, wenn einer ihrer Eingabewerte nicht numerisch ist oder eine ungültige Operation (z.B. Division durch 0) versucht wird.
Funktionen mit einem FensterTitel-Parameter (mit Ausnahmen, wie z.B. der ahk_group-Modus von WinClose) lösen eine Ausnahme aus, wenn das Zielfenster oder -steuerelement nicht gefunden wird.
Ausnahmen werden für einige Fehler ausgelöst, die früher nicht erkannt wurden, und einige Bedingungen, die fälschlicherweise als Fehler markiert wurden (früher durch ErrorLevel-Setzung), wurden behoben.
Einige Fehlermeldungen wurden geändert.
Die Syntax für Catch wurde geändert, um die Möglichkeit zu bieten, bestimmte Error-Klassen abzufangen und den Rest gewähren zu lassen (um die Kontrolle an ein anderes Catch weiter oben im Aufrufstapel zu übergeben oder um den Fehler zu melden und den Thread zu beenden). Früher war es erforderlich, geworfene Werte aller Typen abzufangen, den Typ zu überprüfen und dann erneut zu werfen. Zum Beispiel:
; Alt (verwendet veraltete v2.0-a-Regeln zur Veranschaulichung, da v1 kein `is` oder keine Error-Klassen hatte) try SendMessage Mld,,, "Strlmnt1", "Das Fenster" catch err if err is TimeoutError MsgBox "Das Fenster reagiert nicht" else throw err ; Neu try SendMessage Mld,,, "Strlmnt1", "Das Fenster" catch TimeoutError MsgBox "Das Fenster reagiert nicht"
Variationen:
catch
fängt eine Error-Instanz ab.catch as err
fängt eine Error-Instanz ab, die an err zugewiesen wird.catch ValueError as err
fängt eine ValueError-Instanz ab, die an err zugewiesen wird.catch ValueError, TypeError
fängt beide Typen ab.catch ValueError, TypeError as err
fängt beide Typen ab und weist die Instanz err zu.catch Any
fängt alles ab.catch (MeinError as err)
erlaubt runde Klammern, wie die meisten anderen Kontrollanweisungen auch.Wenn Try ohne Finally oder Catch verwendet wird, verhält es sich so, als hätte es ein Catch mit leerem Block. Dies klingt wie v1, aber Catch allein fängt jetzt nur noch Instanzen von Error ab. In den meisten Fällen ist Try allein dazu gedacht, ein Error zu unterdrücken, so dass keine Änderung vorgenommen werden muss. Allerdings ist das direkte v2-Äquivalent von v1 try irgendwas()
folgendes:
try irgendwas() catch Any {}
Die Priorisierung des Fehlertyps gegenüber dem Namen der Ausgabevariable könnte zu besserem Code ermutigen, d.h. den erwarteten Fehler wie vorgesehen zu behandeln, ohne unerwartete Fehler, die hätten gemeldet werden sollen, zu unterdrücken oder falsch zu behandeln.
Da Werte aller Typen geworfen werden können, ist jede Klasse für den Filter gültig (z.B. String
oder Map
). Die Klassenprototypen werden jedoch beim Laden des Skripts aufgelöst und müssen als vollständiger Klassenname und nicht als beliebiger Ausdruck angegeben werden (ähnlich wie y
in class x extends y
).
Während eine Catch-Anweisung ausgeführt wird, kann throw
(ohne Parameter) verwendet werden, um die Ausnahme erneut zu werfen (wodurch die Notwendigkeit vermieden wird, eine Ausgabevariable nur für diesen Zweck anzugeben). Dies wird sogar innerhalb einer verschachtelten Try-Finally-Anweisung unterstützt, aber nicht innerhalb einer verschachtelten Try-Catch-Anweisung. Das throw
muss nicht physisch im Körper der Catch-Anweisung enthalten sein; sie kann von einer aufgerufenen Funktion verwendet werden.
Ein Else kann nach dem letzten Catch angegeben werden; es wird ausgeführt, wenn innerhalb von Try keine Ausnahme geworfen wird.
Es sind weniger VK-zu-SC- und SC-zu-VK-Belegungen hartkodiert, was theoretisch die Kompatibilität mit unkonventionellen benutzerdefinierten Tastaturbelegungen verbessert.
Die Tastennamen "Return" und "Break" wurden entfernt. Verwenden Sie stattdessen "Enter" und "Pause".
Die Existenz von AltGr auf jeder Tastaturbelegung wird jetzt immer durch Lesen des Flags KLLF_ALTGR aus der Tastaturlayout-DLL erkannt. (v1.1.28+ Unicode Builds verwenden diese Methode bereits.) Die Fallback-Methoden zur Erkennung von AltGr über den Tastatur-Hook wurden entfernt.
Mausrad-Hotkeys setzen A_EventInfo auf den vom Maustreiber gemeldeten Delta-Wert, anstatt diesen Wert durch 120 zu teilen. Normalerweise ist dies ein mit 120 multiplizierter Wert, aber einige Maustreiber können Mausraddrehungen in höherer Auflösung melden.
Hotstrings behandeln nun Umschalt+Backspace wie Backspace, anstatt es innerhalb des Hotstring-Puffers in `b
zu übersetzen.
Hotstrings verwenden das erste Doppelpunktpaar (::
) als Separator, nicht das letzte, wenn mehrere Doppelpunktpaare vorhanden sind. Mit anderen Worten, in v2 müssen Doppelpunkte (die an einen anderen Doppelpunkt angrenzen) im Auslösetext mit einem Escapezeichen versehen werden, während sie in v1 im Ersatztext mit einem Escapezeichen versehen werden müssen. Beachten Sie, dass früher bei einer ungeraden Anzahl aufeinanderfolgender Doppelpunkte der letzte Doppelpunkt nicht als Teil eines Paares interpretiert wurde. Zum Beispiel gibt es keine Änderung im Verhalten von ::1:::2
(1
→ :2
), aber ::3::::4
ist jetzt 3
→ ::4
statt 3::
→ 4
.
Hotstrings escapen Doppelpunkte nicht mehr paarweise, daher ist es nun möglich, einen einzelnen Doppelpunkt am Ende des Auslösetexts mit einem Escapezeichen zu versehen. Zum Beispiel ist ::5`:::6
nun 5:
→ 6
statt eines Fehlers, und ::7`::::8
ist nun 7:
→ :8
statt 7::
→ 8
. In solchen Fällen ist es am besten, alle direkt geschriebenen Doppelpunkte (außer einzelne isolierte Doppelpunkte) mit einem Escapezeichen zu versehen.
Hotstrings mit Fortsetzungsbereichen verwenden nun standardmäßig den Text- statt Raw-Modus.
Hotkeys maskieren die Win/Alt-Taste nur noch beim Loslassen, wenn sie logisch unten ist und der Hotkey die Win/Alt-Taste benötigt (mit #
/!
oder einem benutzerdefinierten Präfix). Das heißt, dass Hotkeys, die die Win/Alt-Taste nicht benötigen, Win/Alt-Up nicht mehr maskieren, wenn die Win/Alt-Taste physisch unten ist. Dadurch können Hotkeys, die {Blind}{LWin up}
senden, das Startmenü aktivieren (dies war bereits mit einer neubelegten Taste wie AppsKey::RWin
möglich).
Die Unterstützung für Windows 2000 und Windows XP wurde eingestellt.
AutoHotkey überschreibt bei der Startphase nicht mehr die Systemeinstellung ForegroundLockTimeout
.
SystemParametersInfo
mit der SPI_SETFOREGROUNDLOCKTIMEOUT
-Aktion erreicht, die Einfluss auf alle Anwendungen für die aktuelle Benutzersitzung hatte. Diese Einstellung blieb zwar nach dem Abmelden nicht erhalten, war aber dennoch für einige Benutzer unerwünscht.SetForegroundWindow
-Aufrufe schlugen immer fehl, und andere von WinActivate angewendete Workarounds waren unabhängig vom Timeout notwendig und aktiv. SPI_GETFOREGROUNDLOCKTIMEOUT
wurde von einem separaten Prozess verwendet, um zu verifizieren, ob die Änderung einen Effekt hatte (was manchmal nicht der Fall war).DllCall("SystemParametersInfo", "int", 0x2001, "int", 0, "ptr", 0, "int", 2)
RegEx-Zeilenumbruchsübereinstimmung verwendet standardmäßig (*ANYCRLF) und (*BSR_ANYCRLF); `r und `n werden zusätzlich zu `r`n erkannt. Die `a-Option aktiviert implizit (*BSR_UNICODE).
RegEx-Callout-Funktionen können nun variadisch sein. Callouts, die über eine pcre_callout
-Variable angegeben werden, können beliebige aufrufbare Objekte sein. pcre_callout
selbst kann direkt als Funktion (evtl. verschachtelte Funktion) definiert werden. Da die Namensräume von Funktionen und Variablen zusammengeführt wurden, kann ein Callout-Muster wie (?C:fn)
auch auf eine lokale oder globale Variable verweisen, die ein Funktionsobjekt enthält, nicht nur auf eine benutzerdefinierte Funktion.
Skripte, die von der Standardeingabe (stdin) gelesen werden (z.B. mit AutoHotkey.exe *
), fügen das ursprüngliche Arbeitsverzeichnis nicht mehr in A_ScriptFullPath oder in den Titel des Hauptfensters ein, aber verwenden es als A_ScriptDir und zum Lokalisieren des lokalen Lib-Ordners.
Einstellungen, die via Auto-Execute-Thread geändert werden, werden jetzt sofort zu Standardeinstellungen gemacht (für Threads, die nach diesem Punkt gestartet werden), nicht erst nach 100 ms und dann noch einmal, wenn der Auto-Execute-Thread sein Ende erreicht hat.
Folgende Limitierungen wurden durch Zuhilfenahme dynamischer Speicherreservierungen beseitigt:
ListVars zeigt jetzt statische Variablen getrennt von lokalen Variablen an. Globale Variablen, die innerhalb der Funktion deklariert sind, werden ebenfalls als statische Variablen aufgelistet (dies ist ein Nebeneffekt neuer Implementierungsdetails, wird aber beibehalten, da es in Skripten mit vielen globalen Variablen nützlich sein könnte).
Die (undokumentierte?) "lose" Variablenoptimierung wurde entfernt, um Codegröße und Wartungskosten zu reduzieren. Diese Optimierung verbesserte die Performanz von Skripten mit mehr als 100000 Variablen.
Tray-Menü: Das Wort "This" wurde aus "Reload This Script" und "Edit This Script" entfernt, um mit "Pause Script" und den Menüoptionen des Hauptfensters konsistent zu sein.
YYYYMMDDHH24MISS-Zeitstempelwerte werden jetzt als ungültig eingestuft, wenn ihre Länge nicht eine gerade Zahl im Bereich von 4 bis 14 ist.
Skripte sind "persistent", wenn mindestens eine der folgenden Bedingungen zutrifft:
Persistent()
oder Persistent(true)
wurde aufgerufen und nicht durch Aufruf von Persistent(false)
rückgängig gemacht.Wenn eines der folgenden Fälle eintritt und keine der obigen Bedingungen zutrifft, wird das Skript terminiert.
Aus Flexibilitätsgründen macht OnMessage das Skript nicht automatisch persistent.
v1-Skripte sind hingegen "persistent", wenn mindestens eine der folgenden Bedingungen zutrifft:
Threads beginnen mit einem unterbrechungsfreien Timeout von 17 ms statt 15 ms. 15 war zu niedrig, da der systeminterne Taktzähler in Schritten von mindestens 15 oder 16 aktualisiert wurde, d.h. wenn der Taktzähler genau zum falschen Zeitpunkt aktualisiert wurde, konnte der Thread unterbrechbar werden, obwohl praktisch keine Zeit vergangen war.
Threads, die unterbrechungsfrei beginnen, bleiben nun solange bestehen, bis mindestens eine Zeile ausgeführt wurde, auch dann, wenn das unterbrechungsfreie Timeout zuerst abläuft (z.B. wenn das System den Prozess unmittelbar nach dem Start des Threads sperrt, um einem anderen Prozess CPU-Zeit zu geben).
#MaxThreads und #MaxThreadsPerHotkey machen keine Ausnahmen mehr für Subroutinen, deren erste Zeile einer der folgenden Befehle ist: ExitApp, Pause, Edit, Reload, KeyHistory, ListLines, ListVars oder ListHotkeys.
#SingleInstance Prompt
kann auch explizit verwendet werden, um Klarheit zu schaffen oder um eine frühere Direktive zu überschreiben.Wenn eine AutoHotkey-Programmdatei (z.B. AutoHotkey32.exe oder AutoHotkey64.exe) ohne Angabe einer Skriptdatei gestartet wird, wird nicht mehr im Ordner "Dokumente" des Benutzers nach einer Standardskriptdatei gesucht.
AutoHotkey ist nicht für den direkten Start der Programmdatei vorgesehen, es sei denn, Sie verwenden eine portable Kopie. Anstatt die Programmdatei auszuführen, sollten Sie in der Regel eine .ahk-Datei ausführen.
Wenn Sie eine Verknüpfung zu einer bestimmten Programmdatei erstellen, können Sie ein Leerzeichen und den Pfad eines Skripts (normalerweise in Anführungszeichen) an das Ziel der Verknüpfung anfügen.
Befehlszeilenargumente werden nicht mehr in ein Pseudo-Array nummerierter globaler Variablen gespeichert; verwenden Sie stattdessen die globale Variable A_Args (verfügbar seit v1.1.27).
Die Optionen /R und /F wurden entfernt. Verwenden Sie stattdessen /restart und /force.
/validate sollte anstelle von /iLib verwendet werden, wenn ein Skript mit AutoHotkey.exe auf Syntaxfehler geprüft wird, da der Mechanismus zum automatischen Inkludieren von Funktionsbibliotheken entfernt wurde.
/ErrorStdOut wird jetzt in einem der folgenden Fälle als Skriptparameter behandelt, nicht intern:
=
beginnt (früher wurde das Suffix ignoriert).