Skriptkompatibilität

Obwohl viele Skripte, die für AutoHotkey v1.0 geschrieben wurden, für AutoHotkey v1.1 nicht geändert werden müssen, kann es vorkommen, dass einige Skripte nicht richtig funktionieren, weil beide Versionen notwendige Unterschiede aufweisen. Die meisten Benutzer müssen sich keine Sorgen machen, da die problematischen Unterschiede nur erweiterte Funktionalitäten wie DllCall() betreffen.

AutoHotkey v1.1 ist auch unter den Namen "AutoHotkey_L" bekannt. AutoHotkey v1.0 trägt seit einiger Zeit den Namen "AutoHotkey Basic". Es gibt einige ältere Versionen von AutoHotkey_L, die eine Versionsnummer im Format 1.0.* haben, daher verwendet dieses Dokument die Namen der beiden AutoHotkey-Zweige, um Missverständnissen vorzubeugen.

Hinweis: Einige der am häufigsten auftretenden Probleme sind auf Änderungen bzgl. der Unterstützung von Unicode-Text zurückzuführen. Mit der ANSI-Version von AutoHotkey_L können solche Probleme umgangen werden.

Inhaltsverzeichnis

Grundlagen

Hohe Auswirkung:

Mittlere Auswirkung:

Geringe Auswirkung:

Erweitert

Grundlagen

Syntaxfehler

Bestimmte Syntaxfehler, die bei AutoHotkey Basic toleriert wurden, sind bei AutoHotkey_L nicht mehr erlaubt. Viele dieser Fehler können leicht korrigiert werden, sobald sie entdeckt werden. In AutoHotkey_L werden die folgenden Fehler sofort nach dem Start eines Skripts erkannt - solche Fehler müssen korrigiert werden, damit das Skript lauffähig ist:

Einige Syntaxfehler werden während der Skriptausführung erkannt. Das Skript wird eine Fehlermeldung anzeigen, bevor es den aktuellen Thread verlässt:

Andere Syntaxfehler werden aktuell nicht erkannt, aber verursachen Probleme mit AutoHotkey_L:

FileRead

In bestimmten Fällen übersetzt FileRead den Text in eine andere Codepage und kann daher fehlerhafte Binärdaten ausgeben. Um das zu verhindern, fügen Sie die *c-Option hinzu oder nutzen Sie stattdessen FileOpen().

Variablen- und Funktionsnamen

Die Zeichen [, ] und ? sind für die Nutzung in Ausdrücken reserviert und daher nicht mehr in Variablennamen gültig. Folglich benötigt ? (das in ternären Operationen benutzt wird) kein Leerzeichen mehr auf beiden Seiten. Siehe auch Objektsyntax.

Fehler werden oder werden nicht automatisch erkannt:

DPI-Skalierung

Die DPI-Skalierung ist standardmäßig für Skript-GUIs aktiviert, um sicherzustellen, dass sie gemäß den systeminternen DPI-Einstellungen skaliert werden. Wenn sie aktiviert ist und die systeminterne DPI-Einstellung ungleich 96 (100 %) ist, sind Positionen und Größen, die von Gui-Befehlen akzeptiert oder zurückgegeben werden, nicht mit anderen Befehlen kompatibel. Die DPI-Skalierung kann mit Gui -DPIScale deaktiviert werden.

Transform

Einige Transform-Unterbefehle wurden in den Unicode-Versionen von AutoHotkey_L geändert oder deaktiviert:

Standardskript

Startet man AutoHotkey_L ohne Angabe eines Skripts, wird standardmäßig eine AHK-Datei anstelle einer INI-Datei geladen. Der Name dieser Datei basiert auf dem Dateinamen der aktuellen EXE-Datei. Weitere Informationen finden Sie unter Befehlszeilenparameter an ein Skript übergeben.

SetFormat, Integer[Fast], H

Verwendet man ein großes H, werden die Hexadezimalzeichen A-F auch in Großbuchstaben sein. AutoHotkey Basic verwendet hingegen immer Kleinbuchstaben. Siehe SetFormat.

A_LastError

Die folgenden Befehle setzen nun A_LastError, um das Debuggen zu unterstützen: FileAppend, FileRead, FileReadLine, FileDelete, FileCopy, FileMove, FileGetAttrib/Time/Size/Version, FileSetAttrib/Time, FileCreateDir, RegRead, RegWrite, RegDelete. Sobald man einen dieser Befehle benutzt, wird der vorherige Wert von A_LastError überschrieben.

MsgBox

Die smarte Kommabehandlung des MsgBox-Befehls wurde geändert, um ihn flexibler und konsistenter mit anderen Befehlen zu machen. In den meisten Fällen wird sich der MsgBox-Befehl wie vorgesehen verhalten. In einigen seltenen Fällen kann es vorkommen, dass sich Skripte, die noch auf das alte, sonderbare Verhalten angewiesen sind, anders als sonst verhalten werden. Zum Beispiel:

; Dies wird nun getrennt 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

Wendet man die +Owner-Option auf eine GUI an, wird zusätzlich der WS_CHILD-Style entfernt und der WS_POPUP-Style gesetzt. Diese Änderung kann dazu führen, dass Skripte, die das übergeordnete Fenster einer GUI mit +Owner setzen, nachdem die Styles gesetzt wurden, nicht mehr ordnungsgemäß funktionieren.

Sound-Befehle in Windows Vista oder höher

SoundSet, SoundGet, SoundSetWaveVolume und SoundGetWaveVolume werden in Windows Vista oder höher besser unterstützt. Folgende Änderungen treten dabei in Kraft:

Tilde-Präfix und benutzerdefinierte Kombinationen

In [v1.1.14+] beeinflusst das Tilde-Präfix das Verhalten einer Taste, die als Modifikatortaste in einer benutzerdefinierten Tastenkombination verwendet wird.

Benutzerdefinierte Kombinationen und Taste-Unten/Oben-Hotkeys

Wenn sowohl ein Taste-Unten- als auch Taste-Oben-Hotkey für eine benutzerdefinierte Modifikatortaste ohne Tilde-Präfix definiert sind, werden beide beim Loslassen der Taste ausgelöst. Zum Beispiel würde x & y:: bewirken, dass x:: und x up:: ausgelöst werden, wenn x losgelassen wird. Früher wurde x:: dabei nie ausgelöst.

If Var is [not] Typ

If Var is [not] Typ ignoriert die Sprach- und Regionseinstellungen des Systems, es sei denn, StringCaseSense Locale wurde verwendet.

Fenstergruppen

GroupActivate setzt ErrorLevel auf 1, wenn kein einziges Fenster aktiviert werden konnte, andernfalls auf 0. Früher blieb ErrorLevel unverändert.

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

Run / RunWait

AutoHotkey_L enthält Verbesserungen hinsichtlich dessen, wie Run und RunWait ihren Ziel-Parameter interpretieren. Diese Verbesserungen bieten neue Möglichkeiten, die früher nicht möglich waren, können aber bestehende Skripte beeinträchtigen, die unter AutoHotkey Basic liefen. Das neue Verhalten äußert sich 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 wird unverändert geladen, selbst wenn es ganz am Ende einer Datei steht. FileRead ignoriert dieses Zeichen bereits und ist daher von diesem Problem nicht betroffen.

Kompatibilitätsmodus

Wenn Sie im Eigenschaftsfenster der EXE-Datei, mit der das Skript ausgeführt werden soll, den Kompatibilitätsmodus auf Windows 95, NT4 oder 98/ME setzen, kann es vorkommen, dass sich das Skript je nach Inhalt falsch verhält. Das liegt daran, dass der Kompatibilitätsmodus dem Programm eine bestimmte Version von Windows meldet, die AutoHotkey_L nicht unterstützt. Setzt man bspw. den Kompatibilitätsmodus auf Windows 95 oder 98/ME, würde MsgBox %A_OSVersion% die Version WIN_NT4 melden.

A_IsCompiled

A_IsCompiled enthält eine leere Zeichenkette, wenn das Skript nicht kompiliert ist. Früher blieb sie undefiniert, wodurch Zuweisungen wie A_IsCompiled := 1 in einem unkompilierten Skript möglich waren. Nun wird sie in jedem Fall als schreibgeschützte interne Variable behandelt.

Escapezeichenversehene Leerraumzeichen

Escapezeichenversehene Leerraumzeichen wie `t und ` werden nicht länger am Anfang oder am Ende eines Arguments verworfen. Zum Beispiel ist StringReplace s, s, `t nun gültig und wird alle Tabulatorzeichen aus s entfernen.

Unicode vs. ANSI

Hinweis: Dieser Abschnitt baut auf Themen auf, die in anderen Teilen der Dokumentation behandelt werden: Zeichenketten (Strings), Zeichenkettenkodierung.

Innerhalb einer Zeichenkette (Textwert) ist der numerische Zeichencode und die Größe (in Bytes) jedes einzelnen Zeichens von der nativen Kodierung des Skripts und von der AutoHotkey-EXE-Datei abhängig; also 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 für AutoHotkey Basic geschrieben wurden, mit der ANSI-Version von AutoHotkey_L korrekt funktionieren, aber nicht mit der Unicode-Version. Mit dem folgenden Skript kann man herausfinden, welche Version gerade verwendet wird:

MsgBox % A_IsUnicode ? "Unicode" : "ANSI"

ANSI: Jedes Zeichen ist ein Byte groß (8 Bits). Zeichencodes über 127 sind von den Spracheinstellungen Ihres 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-Codeeinheiten vertreten, ugs. "Ersatzzeichenpaar" (surrogate pair). Ebenso enthalten einige ANSI-Codepages (ugs. Doppelbyte-Zeichensätze) einige Doppelbyte-Zeichen. Aus praktischen Gründen werden diese jedoch fast immer als zwei einzelne Einheiten behandelt (der Einfachheit halber als "Zeichen" bezeichnet).

VarSetCapacity

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

VarSetCapacity(ansi_var,    capacity_in_chars)
VarSetCapacity(unicode_var, capacity_in_chars * 2)
VarSetCapacity(native_var,  capacity_in_chars * (A_IsUnicode ? 2 : 1))
VarSetCapacity(native_var,  t_size(capacity_in_chars))  ; siehe unten

Es gibt zwei Anwendungsmöglichkeiten für VarSetCapacity:

  1. Eine Variable auf eine ungefähre Anzahl von Zeichen erweitern, um die Verkettung von Zeichenketten performanter zu machen. Zum Beispiel ermöglicht VarSetCapacity(var, 1000) eine Kapazität von 1000 Bytes, die in den Unicode-Versionen von AutoHotkey_L nur für 500 Zeichen ausreichen würde. Das könnte Einfluss auf die Performanz haben, aber das Skript selbst sollte weiterhin normal funktionieren.
  2. Die Größe einer Variable für eine Binärstruktur anpassen. Wenn die Struktur explizit Text enthält, muss das Format des Textes berücksichtigt werden. Das hängt von der Struktur ab - manchmal wird ANSI-Text auch in einer Unicode-Version von AutoHotkey_L verwendet. Wenn die Variable zu klein ist, kann das Skript abstürzen oder sich falsch verhalten (abhängig davon, wie die Struktur verwendet wird).

DllCall

Verwendet man den "Str"-Typ, handelt es sich um 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-TypenKodierung
WStr16-Bitwchar_t*, WCHAR*, LPWSTR, LPCWSTRUTF-16
AStr8-Bitchar*, CHAR*, LPSTR, LPCSTRANSI (die Standard-ANSI-Codepage des Systems)
Str--TCHAR*, LPTSTR, LPCTSTRÄquivalent zu WStr in Unicode-Builds und AStr in ANSI-Builds.

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

Hinweis: "AStr" und "WStr" können sowohl für die Parameter als auch für den Rückgabewert der Funktion verwendet werden.

Wenn ein Skript eine Funktion via DllCall() aufruft, die eine Zeichenkette als Parameter akzeptiert, muss eine der folgenden Vorgehensweisen verwendet werden:

  1. Wenn sowohl die Unicode- (W) als auch die ANSI-Version (A) der Funktion verfügbar sind, rufen Sie je nach aktuellem Build die entsprechende Version auf. Im folgenden Beispiel ist "DeleteFile" intern als "DeleteFileA" oder "DeleteFileW" bekannt. Da "DeleteFile" selbst nicht wirklich existiert, wird DllCall() je nach aktuellem Build automatisch "A" oder "W" anfügen:
    DllCall("DeleteFile", "Ptr", &DateiName)
    DllCall("DeleteFile", "Str", DateiName)

    In diesem Beispiel übergibt &DateiName die Adresse der Zeichenkette, so dass die Funktion eine Zeichenkette im gleichen Format wie der "Str"-Typ erwarten muss. Beachten Sie, dass in AutoHotkey Basic "UInt" statt "Ptr" verwendet werden muss, aber der resultierende Code möglicherweise nicht 64-Bit-kompatibel ist.

    Hinweis: Wenn der Name der Funktion nicht gefunden werden kann, fügt AutoHotkey_L das Suffix "A" oder "W" an, egal welche DLL angegeben ist. AutoHotkey Basic hingegen fügt das Suffix "A" nur bei Funktionen in User32.dll, Kernel32.dll, ComCtl32.dll oder Gdi32.dll an.

  2. Wenn die Funktion nur einen bestimmten Zeichenkettentyp als Eingabe akzeptiert, kann das Skript den entsprechenden Zeichenkettentyp verwenden:
    DllCall("DeleteFileA", "AStr", DateiName)
    DllCall("DeleteFileW", "WStr", DateiName)
  3. Wenn die Funktion eine Zeichenkette (in einem nicht-nativen Format) modifizieren muss, muss das Skript wie oben beschrieben Pufferspeicher reservieren und dessen Adresse an die Funktion übergeben. Wenn der Parameter eine Eingabe akzeptiert, muss das Skript die eingehende Zeichenkette zudem in das passende Format umwandeln, z.B. mit StrPut().

NumPut / NumGet

Verwendet man NumPut() oder NumGet() mit Zeichenketten, muss der korrekte Offset und Typ für den angegebenen Zeichenkettentyp angegeben werden. Folgendes kann Ihnen dabei helfen:

;  8-Bit/ANSI   Zeichenketten:  size_of_char=1  type_of_char="Char"
; 16-Bit/UTF-16 Zeichenketten:  size_of_char=2  type_of_char="UShort"
nth_char := NumGet(var, (n-1)*size_of_char, type_of_char)
NumPut(nth_char, var, (n-1)*size_of_char, type_of_char)

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

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

; Definieren Sie 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 und in 64-Bit-Builds 8 Bytes groß. Skripte, die Strukturen oder DllCalls verwenden, sollten das berücksichtigen, um eine korrekte Ausführung auf beiden Plattformen zu gewährleisten. Bestimmte Bereiche, die auch betroffen sind:

Für Größen- und Offset-Berechnungen kann A_PtrSize verwendet werden. Für DllCall(), NumPut() und NumGet() kann je nach Bedarf der Ptr-Typ verwendet werden.

Beachten Sie, dass der Offset eines Feldes üblicherweise die Gesamtgröße aller vorherigen Felder ist. Beachten Sie 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")