Skript-Kompatibilität

Viele Skripte, die noch auf AutoHotkey 1.0 basieren, müssen nicht für AutoHotkey 1.1 geändert werden. Bei wenigen Ausnahmen können aber aufgrund von notwendigen Unterschieden zwischen den zwei Versionen Probleme auftreten. Da die meisten problematischen Unterschiede nur erweiterte Funktionalitäten wie DllCall betreffen, müssen sich die meisten Benutzer keine Sorgen machen.

AutoHotkey 1.1 kennt man auch unter den Namen "AutoHotkey_L". AutoHotkey 1.0 hat seit längere Zeit die Bezeichnung "AutoHotkey Basic". Einige alte Versionen von AutoHotkey_L benutzten 1.0.* als Versionsnummer, daher wird sich dieses Dokument auf die Namen statt Versionsnummern der beiden Entwicklungszweige von AutoHotkey beziehen.

Hinweis: Einige der häufigsten Probleme rühren daher, dass Änderungen vorgenommen worden sind, um Unicode-Text unterstützen zu können. Mit der ANSI-Version von AutoHotkey_L können solche Probleme umgangen werden.

Grundlagen

Hohe Auswirkung:

Mittlere Auswirkung:

Niedrige Auswirkung:

Erweitert

Grundlagen

Syntaxfehler

Bestimmte Syntaxfehler, die bei AutoHotkey Basic toleriert wurden, sind bei AutoHotkey_L nicht mehr zugelassen. Viele dieser Fehler kann man einfach korrigieren, sobald sie entdeckt werden. Die folgenden Fehler werden sofort nach dem Starten eines Skripts erkannt, und müssen korrigiert werden, bevor das Skript startet:

Einige andere Syntaxfehler werden erkannt, während das Skript läuft. Das Skript wird eine Fehlermeldung anzeigen, bevor es den aktuellen Thread verlässt:

Andere Syntaxfehler wiederrum werden überhaupt nicht erkannt, was bei AutoHotkey_L zu Problemen führen kann:

FileRead

FileRead wandelt den Zeichensatz des Textes in bestimmten Fällen um, wodurch unbrauchbare Binärdaten entstehen können. Um das zu verhindern, benutze die *c-Option oder verwende stattdessen FileOpen.

Variablen- und Funktionsnamen

Die Zeichen [, ] und ? sind für die Verwendung in Ausdrücken reserviert und daher nicht länger in Variablennamen gültig. Folglich benötigt ? (das für ternären Operationen gilt) nicht länger ein Leerzeichen auf jeder Seite. Siehe auch Objektsyntax.

Fehler werden automatisch oder überhaupt nicht erkannt, je nachdem, welche Bedingungen zutreffen:

DPI-Skalierung

DPI-Skalierung ist für Skript-GUIs standardmäßig aktiviert, um sicherzustellen, dass sie auf Basis der DPI-Einstellungen des Systems skaliert werden. Wenn aktiviert und wenn DPI-Einstellung des Systems ungleich 96 (100%) ist, sind von Gui-Befehlen akzeptierte oder zurückgegebene Positionen und Größen nicht mit anderen Befehlen kompatibel. Mit Gui -DPIScale kann die Skalierung deaktiviert werden.

Transform

In den Unicode-Versionen von AutoHotkey_L wurden einige Unterbefehle von Transform geändert oder entfernt:

Standard-Skript

Sobald man AutoHotkey_L ohne Angabe eines Skripts startet, wird standardmäßig eine AHK-Datei statt einer INI-Datei geladen. Der Name dieser Datei beruht auf dem Dateinamen der aktuell ausführbaren Datei. Weitere Informationen findet man unter "Befehlszeilenparameter an ein Skript übergeben".

SetFormat, Integer[Fast], H

Gibt man den Großbuchstaben H an, werden hexadezimale Zeichen A-F auch in Großbuchstaben sein. AutoHotkey Basic verwendet hingegen immer Kleinbuchstaben. Siehe SetFormat.

A_LastError

Absofort setzen die folgenden Befehle A_LastError, um das Debuggen zu unterstützen: FileAppend, FileRead, FileReadLine, FileDelete, FileCopy, FileMove, FileGetAttrib/Time/Size/Version, FileSetAttrib/Time, FileCreateDir, RegRead, RegWrite, RegDelete. Das Verwenden einer dieser Befehle wird den vorherigen Wert von A_LastError überschreiben.

MsgBox

Die intelligente Kommahandhabung der MsgBox wurde geändert, um die Flexibilität zu verbessern und Widersprüche bei allen anderen Befehlen zu verringern. In den meisten Fällen verhält sich die MsgBox so wie sie soll. In einigen seltenen Fällen kann man bei Skripten, die noch auf das alte fehlerbehaftete Verhalten angewiesen sind, Änderungen im Verhalten beobachten. Zum Beispiel:

; Dies wird nun als Ausdruck (Optionen) gefolgt von Text (Titel) interpretiert,
; anstatt als einzelner Ausdruck (Text) mit mehreren Teilausdrücken:
MsgBox % x, y
; Mit runden Klammern kann die alte Interpretation erzwungen werden:
MsgBox % (x, y)

; Dies wird nun ein leeres Dialogfenster anzeigen, anstatt den Text "0, Titel":
MsgBox 0, Titel
; Diese verhalten sich in AutoHotkey_L und AutoHotkey Basic wie erwartet:
MsgBox 0, Titel, % ""   ; Zeigt ein leeres Dialogfenster an
MsgBox 0`, Titel        ; Zeigt den Text "0, Titel" an

; Dies wird nun ein leeres Dialogfenster anzeigen, anstatt den Text ", Titel":
MsgBox,, Titel

Gui +Owner

Beim Anwenden der +Owner-Option auf ein GUI wird zusätzlich der WS_CHILD-Style entfernt und der WS_POPUP-Style gesetzt. Dieser Sachverhalt könnte Skripte negativ beeinflussen, die mit +Owner das übergeordnete Fenster eines GUIs setzen, nachdem die Styles festgelegt wurden.

Sound-Befehle in Windows Vista oder höher

SoundSet, SoundGet, SoundSetWaveVolume und SoundGetWaveVolume werden in Windows Vista oder höher besser unterstützt. Typische Veränderungen im Verhalten sind:

Tilde (~) und Hotkeys mit benutzerdefinierten Tastenkombinationen

Seit v1.1.14 hat das Tilde-Präfix Einfluss darauf, wie eine Taste funktioniert, wenn sie als Modifikatortaste in einer benutzerdefinierten Tastenkombination verwendet wird.

Benutzerdefinierte Tastenkombinationen und Down/Up-Hotkeys

Wenn ein KeyDown- und KeyUp-Hotkey für eine benutzerdefinierte Modifikatortaste definiert wurde, werden beide beim Loslassen der Taste ausgelöst (sofern das Tilde-Präfix nicht vorhanden ist). Zum Beispiel würde x & y:: bewirken, dass x:: und x up:: erst ausgelöst werden, wenn x losgelassen wird. Vorher wurde x:: dabei nie ausgelöst.

If Var is Typ

If Var is Typ ignoriert das Gebietsschema des Betriebssystems, sofern StringCaseSense Locale nicht verwendet wird.

Fenstergruppen

GroupActivate setzt ErrorLevel auf 1, wenn kein Fenster gefunden wird, das aktiviert werden kann, ansonsten auf 0. Zuvor blieb ErrorLevel unverändert.

Der Label-Parameter von GroupAdd gilt nicht für eine bestimmte Fensterspezifikation innerhalb der Gruppe, sondern für die gesamte Fenstergruppe. Eine Diskussion zu dieser Änderung kann im Forum gefunden werden. Allerdings ist dieser Parameter nicht empfohlen; stattdessen sollte ErrorLevel nach dem Aufruf von GroupActivate überprüft werden.

Run / RunWait

AutoHotkey_L enthält einige Verbesserungen, wie die Befehle Run und RunWait den Ziel-Parameter interpretieren. Auf diese Weise sind Dinge möglich, die zuvor nicht möglich waren. In einigen seltenen Fällen könnte dies Auswirkung auf Skripte haben, die mit AutoHotkey Basic bereits funktionierten. Das neue Verhalten ist wie folgt:

STRG+Z

Loop Read und FileReadLine interpretieren das Zeichen STRG+Z (0x1A) nicht länger als Dateiendemarke (end-of-file marker). Jedes STRG+Z-Zeichen, selbst wenn es ganz am Ende einer Datei vorkommt, wird geladen, ohne dass es eine Funktion hat. FileRead ignoriert bereits dieses Zeichen und ist daher von diesem Problem nicht betroffen.

Kompatibilitätsmodus

Setzt man den Kompatibilitätsmodus auf Windows 95, NT4 oder 98/ME im Eigenschaftsfenster der EXE-Datei, mit der das Skript ausgeführt werden soll, kann es passieren, dass sich das Skript falsch verhalten wird. Das liegt daran, dass der Kompatibilitätsmodus eine bestimmte Windows-Version an das Programm senden würde, die in AutoHotkey_L nicht mehr unterstützt wird. Setzt man den Kompatibilitätsmodus auf Windows 95 oder 98/ME, würde MsgBox %A_OSVersion% die Version WIN_NT4 melden.

A_IsCompiled

A_IsCompiled ist als leere Zeichenkette definiert, wenn das Skript noch nicht kompiliert wurde. Vorher blieb es undefiniert, wodurch Zuweisungen wie A_IsCompiled := 1 möglich waren, sofern das Skript noch nicht kompiliert wurde. Absofort wird sie überall als schreibgeschützte Built-in-Variable behandelt.

Escapezeichen-versehene Leerraumzeichen

Escapezeichen-versehene Leerraumzeichen wie `t und ` werden nicht länger am Anfang oder am Ende eines Arguments verworfen. Zum Beispiel ist StringReplace s, s, `t nun eine gültige Anweisung, die alle Tabulatorzeichen in s entfernt.

Unicode vs ANSI

Ein Textwert wird häufig Zeichenkette bzw. String genannt, weil jeder Textwert eine Zusammensetzung von mehreren Zeichen ist. Der numerische Zeichencode und die Größe (in Byte) jedes einzelnen Zeichens hängt davon ab, welche Version von AutoHotkey du benutzt: Unicode oder ANSI. Solche Details sind in der Regel nur für Skripte interessant, die folgende Aktionen durchführen:

Skripte, die nur für ein bestimmtes Format gedacht waren, werden oft auf Probleme stoßen, wenn sie mit der falschen AutoHotkey-Version laufen. Zum Beispiel werden einige Skripte, die noch auf AutoHotkey Basic basieren, korrekt mit der ANSI-Version von AutoHotkey_L funktionieren, aber nicht mit der Unicode-Version. Mit dem folgenden Skript kann man rausfinden, welche Version aktuell verwendet wird:

MsgBox % A_IsUnicode ? "Unicode" : "ANSI"

ANSI: Jedes Zeichen ist ein Byte groß (8 Bits). Zeichencodes über 127 sind von den Spracheinstellungen deines Systems abhängig.

Unicode: Jedes Zeichen ist zwei Bytes groß (16 Bits). Zeichencodes sind durch das UTF-16-Format definiert.

Semantischer Hinweis: Technisch gesehen sind einige Unicode-Zeichen durch zwei 16-Bit-Code-Einheiten vertreten, auch allgemein bekannt als "Ersatzzeichenpaar" (surrogate pair). Ebenso enthalten einige ANSI-Zeichensätze (allgemein bekannt als Doppel-Byte-Zeichensätze) einige Doppel-Byte-Zeichen. Allerdings werden solche aus praktischen Gründen fast immer als zwei einzelne Einheiten (bzw. Zeichen) behandelt.

VarSetCapacity

VarSetCapacity bestimmt die Kapazität einer Variable in Bytes. Um die Kapazität einer Variable in Bezug auf die Zeichenanzahl zu setzen, muss die Größe eines Zeichens berücksichtigt werden. Zum Beispiel:

VarSetCapacity(ANSI_Var,    Zeichenkapazität)
VarSetCapacity(Unicode_Var, Zeichenkapazität * 2)
VarSetCapacity(Native_Var,  Zeichenkapazität * (A_IsUnicode ? 2 : 1))
VarSetCapacity(Native_Var,  t_size(Zeichenkapazität))  ; siehe unten

Es gibt zwei Anwendungsmöglichkeiten für VarSetCapacity:

  1. Erweitere eine Variable auf eine ungefähre Anzahl an Zeichen, um die Performance bei der schrittweisen Verkettung einer Zeichenkette zu verbessern. Zum Beispiel würde VarSetCapacity(var, 1000) 1000 Bytes ermöglichen; in den Unicode-Versionen von AutoHotkey_L wären das nur 500 Zeichen. Das könnte Einfluss auf die Performance haben, aber das Skript selbst sollte weiterhin normal funktionieren.
  2. Passe die Größe einer Variable für eine Binärstrukur an. Enthält die Struktur Text, muss das Format des Textes berücksichtigt werden. Das ist abhängig von der Struktur - ANSI-Text wird manchmal auch in einer Unicode-Version von AutoHotkey_L verwendet. Ist die Variable zu klein, kann es passieren, dass das Skript abstürzt oder sich ansonsten unvorhersehbar verhält (abhängig davon, wie die Struktur verwendet wird).

DllCall

Der "Str"-Typ, falls vorhanden, kennzeichnet eine Zeichenkette im nativen Format des aktuellen Builds. Da einige Funktionen möglicherweise Zeichenketten in einem bestimmten Format benötigen oder zurückgeben müssen, stehen folgende Zeichenkettentypen zur Verfügung:

 ZeichengrößeC / Win32-TypenCodierung
WStr16-Bitwchar_t*, WCHAR*, LPWSTR, LPCWSTRUTF-16
AStr8-Bitchar*, CHAR*, LPSTR, LPCSTRANSI (der Standard-ANSI-Zeichensatz des Systems)
Str--TCHAR*, LPTSTR, LPCTSTREntspricht WStr in Unicode-Builds und AStr in ANSI-Builds.

Verwendet man "Str" oder das Gegenstück des aktuellen Builds als Parameter, wird die Adresse der Zeichenkette oder Variable an die Funktion übergeben. Ansonsten wird eine temporäre Kopie der Zeichenkette im gewünschten Format erstellt und diese stattdessen übergeben. In der Regel sollten "AStr" und "WStr" nicht verwendet werden, wenn die Funktion einen Wert in diesen Parameter schreibt.

Hinweis: "AStr" und "WStr" sind sowohl bei Parametern als auch beim Rückgabewert einer Funktion gültig.

Wenn ein Skript eine Funktion via DllCall aufruft, die eine Zeichenkette als Parameter akzeptiert, muss eine der folgenden Methoden durchgeführt werden:

  1. Je nach aktuellem Build sollte man die Unicode- (W) oder ANSI-Version (A) der Funktion aufrufen, falls beide zur Verfügung stehen. Im folgenden Beispiel ist "DeleteFile" intern als "DeleteFileA" oder "DeleteFileW" bekannt. Da "DeleteFile" selbst nicht wirklich existiert, wird DllCall automatisch "A" oder "W" je nach aktuellem Build anfügen:
    DllCall("DeleteFile", "Ptr", &Dateiname)
    DllCall("DeleteFile", "Str", Dateiname)

    In diesem Beispiel wird &Dateiname die Adresse der Zeichenkette exakt in dieser Form übergeben, so dass die Funktion eine Zeichenkette im gleichen Format wie der "Str"-Typ erwarten muss. Beachte, dass in AutoHotkey Basic "UInt" statt "Ptr" verwendet werden muss, aber es kann sein, dass der resultierende Code nicht 64-Bit-kompatibel ist.

    Hinweis: Wenn die Funktion mit exakt diesem Namen nicht auffindbar ist, fügt AutoHotkey_L das Suffix "A" oder "W" an, egal welche DLL-Datei angegeben ist. AutoHotkey Basic hingegen wird den Suffix "A" nur bei Funktionen anfügen, die in User32.dll, Kernel32.dll, ComCtl32.dll oder Gdi32.dll vorkommen.

  2. Wenn die Funktion nur einen bestimmten Zeichenkettentyp als Eingabevariable akzeptiert, könnte das Skript jeweils den passenden Zeichenkettentyp verwenden:
    DllCall("DeleteFileA", "AStr", Dateiname)
    DllCall("DeleteFileW", "WStr", Dateiname)
  3. Wenn die Funktion eine Zeichenkette modifizieren muss (in einem nicht-nativen Format), muss das Skript einen Puffer wie oben beschrieben bereitstellen und deren Adresse an die Funktion übergeben. Wenn der Parameter eine Eingabevariable akzeptiert, muss das Skript die eingehende Zeichenkette zudem in das passende Format umwandeln; verwende dazu StrPut.

NumPut / NumGet

Wenn man NumPut oder NumGet bei Zeichenketten anwendet, muss der korrekte Offset und Typ für den angegebenen Zeichenkettentyp angegeben werden. Das folgende Beispiel könnte dir dabei helfen:

;  8-Bit/ANSI   Zeichenkette:  Zeichengröße=1  Zeichentyp="Char"
; 16-Bit/UTF-16 Zeichenkette:  Zeichengröße=2  Zeichentyp="UShort"
nte_Zeichen := NumGet(var, (n-1)*Zeichengröße, Zeichentyp)
NumPut(nte_Zeichen, var, (n-1)*Zeichengröße, Zeichentyp)

Wenn var eine Zeichenkette im nativen Format enthält, können die passenden Werte auf Basis von A_IsUnicode bestimmt werden:

nte_Zeichen := NumGet(var, t_size(n-1), t_char())
NumPut(nte_Zeichen, var, t_size(n-1), t_char())

; Definiere Funktionen für Komfort und Übersichtlichkeit:
t_char() {
    return A_IsUnicode ? "UShort" : "Char"
}
t_size(char_count=1) {
    return A_IsUnicode ? char_count*2 : char_count
}

Pointer-Größe

Pointer sind in 32-Bit-Builds (einschließlich AutoHotkey Basic) 4 Bytes groß und in 64-Bit-Builds 8 Bytes. Skripte, die Strukturen oder DllCalls verwenden, sollten dies berücksichtigen, so dass sie auf beiden Plattformen richtig laufen können. Bestimmte Bereiche, die auch betroffen sind:

Mit A_PtrSize kann man Größe und Offset berechnen. Je nachdem wo es angebracht ist, kann man den Ptr-Typ bei DllCall, NumPut und NumGet verwenden.

Beachte, dass der Offset eines Felds üblicherweise die Gesamtgröße aller vorherigen Felder ist. Beachte auch, dass Handles (einschließlich Typen wie HWND und HBITMAP) prinzipiell Pointer-Typen sind.

/*
  typedef struct _PROCESS_INFORMATION {
    HANDLE hProcess;    // Ptr
    HANDLE hThread;
    DWORD  dwProcessId; // UInt (4 Bytes)
    DWORD  dwThreadId;
  } PROCESS_INFORMATION, *LPPROCESS_INFORMATION;
*/
VarSetCapacity(pi, A_PtrSize*2 + 8) ; Ptr + Ptr + UInt + UInt
DllCall("CreateProcess", <gekürzt>, "Ptr", &pi, <gekürzt>)
hProcess    := NumGet(pi, 0)         ; Standardmäßig "Ptr".
hThread     := NumGet(pi, A_PtrSize) ;
dwProcessId := NumGet(pi, A_PtrSize*2,     "UInt")
dwProcessId := NumGet(pi, A_PtrSize*2 + 4, "UInt")