Skript-Kompatibilität

Obwohl viele Skripte, die noch auf AutoHotkey 1.0 basieren, nicht für AutoHotkey 1.1 geändert werden müssen, kann es passieren, dass einige Skripte fehlerhaft funktionieren werden, weil beide Versionen notwendige Unterschiede aufweisen. Die meisten Benutzer müssen sich keine Sorgen machen, da die schwerwiegenden Unterschiede nur erweiterte Funktionalitäten wie DllCall betreffen.

AutoHotkey 1.1 kennt man auch unter den Namen "AutoHotkey_L". AutoHotkey 1.0 hat seit längere Zeit die Bezeichnung "AutoHotkey Basic". Ältere Versionen von AutoHotkey_L haben noch eine Versionsnummer im Format 1.0.*, daher wird sich dieses Dokument stattdessen auf die Namen der beiden Entwicklungszweige von AutoHotkey beziehen, um Missverständnisse vorzubeugen.

Hinweis: Einige der häufigsten Probleme werden durch Änderungen verursacht, die erforderlich waren, um Unicode-Text zu unterstützen. 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 können einfach korrigiert werden, sobald sie entdeckt werden. In AutoHotkey_L werden die folgenden Fehler sofort nach dem Starten eines Skripts erkannt - solche Fehler müssen korrigiert werden, um das Skript überhaupt lauffähig zu machen:

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

Andere Syntaxfehler wiederum 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, dadurch kann es passieren, dass dieser Befehl beschädigte Binärdaten zurückgibt. Um dieses Problem zu umgehen, fügt man die *c-Option hinzu oder benutzt stattdessen FileOpen.

Namen von Variablen und Funktionen

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 in ternären Operationen benutzt wird) 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 sie aktiviert ist und wenn die DPI-Einstellung des Systems ungleich 96 (100%) ist, sind Positionen und Größen, die von Gui-Befehlen akzeptiert oder zurückgegeben werden, nicht mit anderen Befehlen kompatibel. Mit Gui -DPIScale kann die DPI-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

Wenn man ein großgeschriebenes H benutzt, werden die hexadezimale Zeichen 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 intelligente Kommahandhabung 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 Skripte, die noch auf das alte fehlerbehaftete Verhalten angewiesen sind, sich 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

Sobald man die +Owner-Option auf eine GUI anwendet, wird außerdem der WS_CHILD-Style entfernt und der WS_POPUP-Style gesetzt. Diese Änderung kann bewirken, dass Skripte, die mit +Owner das übergeordnete Fenster einer GUI nach Festlegen der Styles setzen, nicht mehr ordnungsgemäß funktionieren werden.

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 (~) und Hotkeys mit benutzerdefinierten Tastenkombinationen

In [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 einziges Fenster aktiviert werden konnte, ansonsten auf 0. Zuvor blieb ErrorLevel unverändert.

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

Run / RunWait

AutoHotkey_L enthält Verbesserungen bezüglich der Verfahrensweise, wie Run und RunWait ihren Ziel-Parameter interpretieren. Diese Verbesserungen bieten neue Möglichkeiten, die zuvor nicht möglich waren, aber können bereits existierende Skripte beeinträchtigen, die auf Basis von AutoHotkey Basic erstellt wurden. 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-Zeichen wird so wie es ist geladen, selbst wenn es ganz am Ende einer Datei vorkommt. 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 wird 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. Jedenfalls wird sie nun als schreibgeschützte interne 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 als Zeichenkette bzw. String bezeichnet, weil jeder Textwert aus einer Kette oder Sequenz von Zeichen besteht. Der numerische Zeichencode und die Größe (in Byte) jedes einzelnen Zeichens hängt davon ab, welche Version von AutoHotkey Sie nutzen: 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 herausfinden, 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 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-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. Erweitern Sie 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. Passen Sie die Größe einer Variable für eine Binärstruktur 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. Beachten Sie, 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 (in einem nicht-nativen Format) modifizieren muss, 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; verwenden Sie 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 Ihnen 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())

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

Beachten Sie, dass der Offset eines Felds ü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")