DllCall()

Ruft eine Funktion aus einer DLL-Datei auf, z.B. eine API-Funktion von Windows.

Ergebnis := DllCall("DllDatei\Funktion" , Typ1, Arg1, Typ2, Arg2, "Cdecl RückgabeTyp")

Parameter

[DllDatei\]Funktion

Der Name einer DLL- oder EXE-Datei, gefolgt von einem umgekehrten Schrägstrich und dem Namen der Funktion. Zum Beispiel: "MeineDLL\MeineFunktion" (wenn die Dateiendung weggelassen wird, wird standardmäßig ".dll" verwendet). Wenn kein absoluter Pfad angegeben ist, wird DllDatei in einem der Pfade aus der PATH-Umgebungsvariable oder im A_WorkingDir-Verzeichnis vermutet. Beachten Sie, dass DllCall() einen Pfad mit umgekehrten Schrägstrichen (\) erwartet. Nach rechts gerichtete Schrägstriche (/) werden nicht unterstützt.

DllDatei kann weggelassen werden, wenn eine Funktion aus den Systemdateien User32.dll, Kernel32.dll, ComCtl32.dll oder Gdi32.dll aufgerufen wird. Zum Beispiel liefert "User32\IsWindowVisible" dasselbe Ergebnis wie "IsWindowVisible".

Wenn unter dem angegebenen Namen keine Funktion gefunden wird, wird automatisch ein A (ANSI) oder W (Unicode) angefügt, je nachdem, mit welcher AutoHotkey-Version das Skript ausgeführt wird. Zum Beispiel ist "MessageBox" dasselbe wie "MessageBoxA" in ANSI-Versionen und dasselbe wie "MessageBoxW" in Unicode-Versionen.

Wenn die DLL wiederholt aufgerufen wird, ist es ratsam, sie vorher zu laden, um die Performanz drastisch zu erhöhen.

[v1.0.46.08+]: Dieser Parameter kann auch ein reiner Integer sein, der als Adresse einer Funktion zum Aufrufen interpretiert wird. Quellen für solche Adressen sind u.a. COM und RegisterCallback().

Typ1, Arg1

Jedes dieser Paare repräsentiert einen einzelnen Parameter, der an die Funktion übergeben werden soll. Die Anzahl der Paare ist unbegrenzt. Geben Sie für Typ einen Typ aus der Typentabelle unten an. Geben Sie für Arg einen Wert an, der an die Funktion übergeben werden soll.

Cdecl RückgabeTyp

Das Wort Cdecl wird normalerweise weggelassen, da die meisten Funktionen die Standardaufrufkonvention anstelle der C-Aufrufkonvention verwenden (Funktionen wie wsprintf, die eine unterschiedliche Anzahl von Argumenten akzeptieren, sind eine Ausnahme). Wenn Cdecl weggelassen wird, aber der Aufruf ErrorLevel An liefert - wobei n die Gesamtgröße der übergebenen Argumente ist - muss Cdecl eventuell angegeben werden. Beachten Sie, dass die meisten objektorientierten C++-Funktionen die nicht unterstützte thiscall-Konvention verwenden.

Das Wort Cdecl muss vor dem Rückgabetyp (falls vorhanden) stehen. Trennen Sie alle Wörter jeweils durch ein Leer- oder Tabulatorzeichen. Zum Beispiel: "Cdecl Str".

[AHK_L 53+]: Da es im 64-Bit-Code keine separate C-Aufrufkonvention gibt, hat die Angabe von Cdecl in 64-Bit-Builds von AutoHotkey keine Wirkung.

RückgabeTyp: Wenn die Funktion einen vorzeichenfähigen 32-Bit-Integer (Int), BOOL oder nichts zurückgibt, kann RückgabeTyp weggelassen werden. Andernfalls geben Sie einen der Argumenttypen aus der Typentabelle unten an. Das Sternchen-Suffix wird ebenfalls unterstützt.

Rückgabewert

DllCall gibt den Rückgabewert von Funktion zurück. Wenn Funktion keinen Rückgabewert hat, ist das Ergebnis ein undefinierter Integer. Wenn Funktion aufgrund eines Fehlers nicht aufgerufen werden kann, ist der Rückgabewert eine leere Zeichenkette.

Typen von Argumenten und Rückgabewerten

Typ Beschreibung
Str

Eine Zeichenkette wie "Blau" oder MeineVar. Wenn die aufgerufene Funktion die Zeichenkette ändert und das Argument eine reine Variable ist, wird der Inhalt der Variable aktualisiert. Zum Beispiel würde der folgende Aufruf den Inhalt von MeineVar in Großbuchstaben umwandeln: DllCall("CharUpper", "Str", MeineVar).

Wenn die Funktion jedoch eine Zeichenkette zurückgibt, die größer ist als die aktuelle Kapazität einer Variable, sollten Sie vor dem Funktionsaufruf sicherstellen, dass die Variable groß genug ist. Rufen Sie hierfür VarSetCapacity(MeineVar, 123) auf, wobei 123 die gewünschte Kapazität für MeineVar ist.

Ein Str-Argument darf kein Ausdruck sein, der nach der Auswertung eine Zahl ergibt (z.B. i+1). Ist dies der Fall, wird die Funktion nicht aufgerufen und ErrorLevel auf -2 gesetzt.

Die Sternchenvariable "Str*" wird unterstützt, aber selten verwendet. Sie kann für Funktionen verwendet werden, die so etwas wie "TCHAR **" oder "LPTSTR *" erwarten.

Hinweis: Wenn Sie eine Zeichenkette an eine Funktion übergeben, müssen Sie darauf achten, welchen Typ von Zeichenkette die Funktion erwartet.

AStr
WStr
[AHK_L 42+]: Eine ANSI- oder Unicode-Zeichenkette (Wide character). Weitere Informationen und äquivalente Win32-Typen finden Sie unter Skriptkompatibilität.
Int64 Ein 64-Bit-Integer im Bereich von -9223372036854775808 (-0x8000000000000000) bis 9223372036854775807 (0x7FFFFFFFFFFFFFFF).
Int

Ein 32-Bit-Integer (der am häufigsten verwendete Integertyp) im Bereich von -2147483648 (-0x80000000) bis 2147483647 (0x7FFFFFFF). Ein Int wird manchmal auch als "Long" bezeichnet.

Ein Int sollte auch für BOOL-Argumente verwendet werden (ein BOOL-Wert ist entweder 1 oder 0).

Ein vorzeichenloser Integer (UInt) ist ebenfalls recht häufig vertreten und kann zum Beispiel für DWORD-Argumente verwendet werden.

Short Ein 16-Bit-Integer im Bereich von -32768 (-0x8000) bis 32767 (0x7FFF). Ein vorzeichenloser 16-Bit-Integer (UShort) kann zum Beispiel für DWORD-Argumente verwendet werden.
Char Ein 8-Bit-Integer im Bereich von -128 (-0x80) bis 127 (0x7F). Ein vorzeichenloser 8-Bit-Integer (UChar) kann zum Beispiel für BYTE-Argumente verwendet werden.
Float Eine 32-Bit-Floating-Point-Zahl mit einer Genauigkeit von 6 Dezimalstellen.
Double Eine 64-Bit-Floating-Point-Zahl mit einer Genauigkeit von 15 Dezimalstellen.
Ptr

[AHK_L 42+]: Ein pointergroßer Integer, äquivalent zu Int oder Int64, je nachdem, ob die EXE-Datei, die das Skript ausführt, 32-Bit oder 64-Bit ist. Ptr sollte für Pointer verwendet werden, die auf Arrays oder Strukturen verweisen (wie RECT* oder LPPOINT), und für fast alle Handles (wie HWND, HBRUSH oder HBITMAP). Wenn der Parameter ein Pointer ist, der auf einen einzelnen numerischen Wert verweist, wie z.B. LPDWORD oder int*, sollte grundsätzlich das *- oder P-Suffix anstelle von "Ptr" verwendet werden.

Ptr kann auch mit dem *- oder P-Suffix verwendet werden; es sollte mit Funktionen verwendet werden, die einen Pointer via LPVOID* oder ähnliches zurückgeben.

UPtr ist auch gültig, ist aber nur vorzeichenlos in 32-Bit-Builds, da AutoHotkey keine vorzeichenlosen 64-Bit-Integer unterstützt.

Wenn das Skript mit älteren Versionen von AutoHotkey kompatibel sein muss, verwenden Sie einen Variablentyp wie folgt:

Ptr := A_PtrSize ? "Ptr" : "UInt" ; Wenn A_PtrSize nicht definiert ist, wird stattdessen UInt verwendet.
DllCall("DeleteFile", Ptr, &DateiName) ; Anführungszeichen bei Ptr weglassen.

Hinweis: Um ein NULL-Handle oder -Pointer zu übergeben, verwenden Sie den Integer 0.

* oder P
(Suffix)

Fügen Sie ein Sternchen (optional mit einem Leerzeichen davor) an einen der obigen Typen an, um nicht den Wert selbst, sondern die Adresse des Arguments zu übergeben (die aufgerufene Funktion muss dafür ausgelegt sein, so etwas zu akzeptieren). Da der Wert eines solchen Arguments von der Funktion geändert werden kann, wird jedes Mal, wenn eine reine Variable als Argument übergeben wird, der Inhalt dieser Variable aktualisiert. Zum Beispiel würde der folgende Aufruf den Inhalt von MeineVar an MeineFunktion via Adresse übergeben, aber auch den Inhalt von MeineVar aktualisieren, um alle Änderungen widerzuspiegeln, die MeineFunktion an MeineVar vorgenommen hat: DllCall("MeineDLL\MeineFunktion", "Int*", MeineVar).

In der Regel wird ein Sternchen verwendet, wenn eine Funktion einen Argument- oder Rückgabetyp hat, der mit "LP" beginnt. Das bekannteste Beispiel dafür ist LPDWORD (ein Pointer, der auf ein DWORD verweist). Da DWORD ein vorzeichenloser 32-Bit-Integer ist, können Sie "UInt*" oder "UIntP" für LPDWORD verwenden. Das Sternchen sollte nicht für Zeichenkettentypen wie LPTSTR, auf Strukturen verweisende Pointer wie LPRECT, oder Arrays verwendet werden; für solche Typen ist "Str" oder "Ptr" besser geeignet, je nachdem, ob Sie eine Variable oder ihre Adresse übergeben.

Hinweis: "Char*" ist nicht dasselbe wie "Str", weil "Char*" die Adresse einer 8-Bit-Zahl übergibt, während "Str" die Adresse einer Zeichenkette übergibt, die je nach AutoHotkey-Version 8-Bit (ANSI) oder 16-Bit (Unicode) ist. Ähnlich verhält es sich mit "UInt*": Da dieser Typ die Adresse einer 32-Bit-Zahl übergibt, ist er nicht für Funktionen geeignet, die ein Array mit Werten oder eine Struktur größer als 32 Bit erwarten.

Da Variablen in AutoHotkey keinen festen Typ haben, verweist eine an die Funktion übergebene Adresse auf einen temporären Speicher, nicht auf die Variable selbst. Es ist nicht notwendig, VarSetCapacity() für die Variable aufzurufen, da DllCall diese Variable nach dem Funktionsaufruf korrekt aktualisieren wird.

U (Präfix)

Stellen Sie einem der obigen Integertypen den Buchstaben U voran, um den entsprechenden Wert als vorzeichenlosen Integer (UInt64, UInt, UShort und UChar) zu interpretieren. Streng genommen ist das nur für Rückgabewerte und Sternchenvariablen notwendig, da es keine Rolle spielt, ob ein via Wert übergebenes Argument vorzeichenfähig oder vorzeichenlos ist (außer für Int64).

Wenn ein negativer Integer bei einem vorzeichenlosen Argument angegeben ist, wechselt der Integer in den vorzeichenlosen Bereich. Zum Beispiel wird -1 zu 0xFFFFFFFF, wenn es als UInt gesendet wird.

Vorzeichenlose 64-Bit-Integer, die von einer Funktion erzeugt werden, werden nicht unterstützt. Um mit Zahlen größer gleich 0x8000000000000000 zu arbeiten, verzichten Sie auf das U-Präfix und interpretieren Sie alle negativen Werte, die von der Funktion zurückgegeben werden, als große Integer (Int64). Zum Beispiel wird eine Funktion, die -1 als Int64 zurückgibt, eigentlich 0xFFFFFFFFFFFFFFFF zurückgeben, wenn sie für die Rückgabe eines UInt64 ausgelegt ist.

Für Parameter vom Typ UInt64 können lange vorzeichenlose Werte als Zeichenketten übergeben werden. Für kleinere Integertypen ohne *- oder P-Suffix oder bei der Übergabe von reinen 64-Bit-Integern an eine Funktion spielt der Unterschied zwischen vorzeichenfähig und vorzeichenlos keine Rolle, weil zum Darstellen von vorzeichenfähigen Integern das Zweierkomplement verwendet wird. Aus Gründen der Übersichtlichkeit kann es jedoch sinnvoll sein, für vorzeichenlose Werte das U-Präfix zu verwenden.

Veraltet: Bei der Angabe eines Argument- oder Rückgabetyps, der kein Leerzeichen oder Sternchen enthält, können die Anführungszeichen weggelassen werden. Zum Beispiel kann Str anstelle von "Str" und CDecl anstelle von "CDecl" verwendet werden. Dies ist nicht für neue Skripte empfohlen.

Fehlerbehandlung

[v1.1.04+]: Diese Funktion ist in der Lage, bei Misserfolg eine Ausnahme auszulösen. Weitere Informationen finden Sie unter Laufzeitfehler.

ErrorLevel wird auf einen der folgenden Werte gesetzt, um den Erfolg oder Misserfolg des Aufrufs zu kennzeichnen.

0: Erfolgreich.

-1: Der [DllDatei\]Funktion-Parameter ist eine Floating-Point-Zahl. Es wird eine Zeichenkette oder ein positiver Integer benötigt.

-2: Der Rückgabetyp oder einer der angegebenen Argumenttypen ist ungültig. Dieser Fehler kann auch auftreten, wenn ein Ausdruck, der nach der Auswertung eine Zahl ergibt, an ein Zeichenkettenargument (Str) übergeben wird.

-3: Die angegebene DllDatei konnte nicht gelesen oder geladen werden. Wenn kein expliziter Pfad für DllDatei angegeben wurde, muss die Datei in einem der Pfade aus der PATH-Umgebungsvariable oder im A_WorkingDir-Verzeichnis vorhanden sein. Dieser Fehler kann auch auftreten, wenn der Benutzer keine Zugriffsrechte auf die Datei hat, oder wenn man mit einem 32-Bit-Build von AutoHotkey auf eine 64-Bit-DLL zugreift (oder umgekehrt).

-4: Die angegebene Funktion konnte in der DLL nicht gefunden werden.

N (beliebige positive Nummer): Die Funktion wurde aufgerufen, aber mit der fatalen Ausnahme Nummer N abgebrochen (z.B. 0xC0000005 bedeutet "Zugriffsverletzung"). In solchen Fällen gibt die Funktion einen leeren Wert (leere Zeichenkette) zurück, während alle Sternchenvariablen weiter aktualisiert werden. Eine fatale Ausnahme ist zum Beispiel die Dereferenzierung eines ungültigen Pointers wie NULL. Da eine Cdecl-Funktion niemals den im nächsten Absatz beschriebenen "An"-Fehler erzeugt, löst die Funktion stattdessen eine Ausnahme aus, wenn ihr zu wenig Argumente übergeben werden.

An (Buchstabe A gefolgt vom Integer n): Die Funktion wurde erfolgreich aufgerufen, aber ihr wurden zu viele oder zu wenig Argumente übergeben. "n" ist die Anzahl der Bytes, um wie viel die Argumentenliste inkorrekt war. Wenn n positiv ist, wurden zu viele Argumente (oder zu lange Argumente) übergeben, oder der Aufruf benötigt CDecl. Wenn n negativ ist, wurden zu wenig Argumente übergeben. Dieser Fehler sollte behoben werden, um einen zuverlässigen Betrieb der Funktion zu gewährleisten. Dieser Fehler kann auch ein Indikator dafür sein, dass eine Ausnahme aufgetreten ist - in diesem Fall gibt die Funktion einen leeren Wert zurück. Beachten Sie, dass 64-Bit-Builds von AutoHotkey aufgrund der x64-Aufrufkonvention nicht in der Lage sind, ErrorLevel auf An zu setzen.

Ausnahmen und A_LastError

Trotz der internen Ausnahmebehandlung kann ein DllCall das Skript immer noch zum Absturz bringen. Dies kann passieren, wenn eine Funktion nicht direkt eine Ausnahme auslöst, sondern etwas Falsches zurückgibt, wie z.B. einen fehlerhaften Pointer oder eine nicht-terminierte Zeichenkette. Dies ist nicht unbedingt die Schuld der Funktion, wenn das Skript ihr einen ungeeigneten Wert übergeben hat, wie z.B. einen fehlerhaften Pointer oder ein "Str" mit unzureichender Kapazität. Ein Skript kann auch abstürzen, wenn es einen ungeeigneten Argument- oder Rückgabetyp spezifiziert, z.B. wenn es behauptet, dass ein gewöhnlicher Integer, der von einer Funktion zurückgegeben wird, eine Sternchenvariable oder Str ist.

Die interne Variable A_LastError enthält den Rückgabewert der Systemfunktion GetLastError(), die unmittelbar nach dem Aufruf der Funktion aufgerufen wird (dies hat keinen messbaren Einfluss auf die Performanz). A_LastError ist eine Zahl zwischen 0 und 4294967295 (immer dezimal, nicht hexadezimal). A_LastError ist wie ErrorLevel eine threadspezifische Einstellung, d.h. es kann nicht durch Unterbrechungen anderer Threads geändert werden. Allerdings wird A_LastError auch von Run/RunWait gesetzt.

Performanz

Wenn die DLL wiederholt aufgerufen wird, ist es ratsam, sie vorher zu laden, um die Performanz drastisch zu erhöhen (das ist für eine Standard-DLL wie User32 nicht notwendig, da sie immer allgegenwärtig ist). Dadurch wird vermieden, dass DllCall jedes Mal LoadLibrary und FreeLibrary intern aufrufen muss. Zum Beispiel:

hModule := DllCall("LoadLibrary", "Str", "MeineFunktionen.dll", "Ptr")  ; Verhindert, dass DllCall() die Bibliothek in der Schleife laden muss.
Loop, C:\Meine Dokumente\*.*, , 1
    Ergebnis := DllCall("MeineFunktionen\DateiSichern", "Str", A_LoopFileFullPath)
DllCall("FreeLibrary", "Ptr", hModule)  ; Um Speicherplatz zu sparen, kann die DLL nach Gebrauch wieder freigegeben werden.

[v1.0.46.08+]: Um die Performanz noch weiter zu erhöhen, kann die Adresse der Funktion im Voraus ermittelt werden. Zum Beispiel:

; Verwenden Sie in der folgenden Zeile LoadLibrary anstelle von GetModuleHandle, wenn die DLL noch nicht geladen ist.
MulDivProc := DllCall("GetProcAddress", "Ptr", DllCall("GetModuleHandle", "Str", "kernel32", "Ptr"), "AStr", "MulDiv", "Ptr")
Loop 500
    DllCall(MulDivProc, "Int", 3, "Int", 4, "Int", 3)

[AHK_L 31+]: Wenn der erste Parameter von DllCall eine direkt geschriebene Zeichenkette wie "MulDiv" ist und die DLL der entsprechenden Funktion normal vor dem Start des Skripts geladen wird, wird die Zeichenkette automatisch in eine Funktionsadresse aufgelöst. Diese interne Optimierung ist effizienter als das obige Beispiel.

Sie können auch #NoEnv irgendwo im Skript einfügen, um die Performanz von DllCall zu erhöhen, wenn anführungszeichenlose Parametertypen verwendet werden (z.B. Int statt "Int").

Übergibt man eine Zeichenkettenvariable an eine Funktion, die die Länge der Zeichenkette nicht ändert, kann die Performanz erhöht werden, indem man die Variable per Adresse (z.B. &MeineVar) statt als "str" übergibt (insbesondere dann, wenn die Zeichenkette sehr lang ist). Das folgende Beispiel wandelt alle Buchstaben einer Zeichenkette in Großbuchstaben um: DllCall("CharUpper", "Ptr", &MeineVar, "Ptr").

Strukturen und Arrays

Eine Struktur ist eine Sammlung von Elementen (Feldern), die nebeneinander im Speicher abgelegt sind. Die meisten Elemente sind für gewöhnlich Integer.

Funktionen, die die Adresse einer Struktur (oder eines Speicherblock-Arrays) akzeptieren, können aufgerufen werden, indem man die rohen Binärdaten der Struktur in einer normalen Variable hinterlegt. In der Regel geht man wie folgt vor:

1) Rufen Sie VarSetCapacity(MeineStrukt, 123, 0) auf, um sicherzustellen, dass die Kapazität der Zielvariable groß genug für die Struktur ist. Ersetzen Sie 123 mit einer Zahl, die mindestens der Größe der Struktur entspricht. Die 0 im letzten Parameter ist optional und bewirkt, dass alle Strukturelemente mit einer binären Null initialisiert werden, um häufige Aufrufe von NumPut() zu vermeiden, wie im nächsten Schritt beschrieben.

2) Wenn die Zielfunktion bereits zu Beginn bestimmte Werte in der Struktur benötigt, rufen Sie NumPut(123, MeineStrukt, 4, "UInt") auf, um ein beliebiges Element auf einen Wert ungleich 0 zu setzen. Ersetzen Sie 123 mit einem Integer, auf dem das Zielelement gesetzt werden soll (oder geben Sie &Var an, um die Adresse einer Variable zu hinterlegen). Ersetzen Sie 4 mit dem Offset des Zielelements (siehe Schritt #4, was ein "Offset" ist). Ersetzen Sie "UInt" mit dem entsprechenden Typ oder lassen Sie es weg, wenn das Element ein Pointer oder Handle ist.

3) Rufen Sie die Zielfunktion auf und übergeben Sie die Adresse von MeineStrukt als UInt (oder als Ptr in [AHK_L 42+]). Zum Beispiel DllCall("MeineDLL\MeineFunk", "Ptr", &MeineStrukt). Die Funktion wird einige Elemente auswerten und/oder ändern.

4) Verwenden Sie MeinInteger := NumGet(MeineStrukt, 4, "UInt"), um einen beliebigen Integer aus der Struktur abzurufen. Ersetzen Sie 4 mit dem Offset des Zielelements in der Struktur. Das erste Element befindet sich immer auf Offset 0. Das zweite Element befindet sich auf Offset 0 plus der Größe des ersten Elements (typischerweise 4). Jedes nachfolgende Element befindet sich auf dem Offset des vorherigen Elements plus der Größe des vorherigen Elements. Die meisten Elemente -- wie z.B. DWORD, Int und andere Typen von 32-Bit-Integern -- haben eine Größe von 4 Bytes. Ersetzen Sie "UInt" mit dem entsprechenden Typ oder lassen Sie es weg, wenn das Element ein Pointer oder Handle ist.

Beispiele für Strukturen finden Sie im Beispielabschnitt weiter unten.

Bekannte Einschränkungen

Übergibt man die Adresse einer Variable (z.B. &MeineVar) an eine Funktion, die die Länge des Variableninhalts ändert, kann es vorkommen, dass die Variable bei späterer Verwendung ein fehlerhaftes Verhalten aufweist. Um das zu verhindern, gibt es folgende Lösungsmöglichkeiten: 1) Übergeben Sie MeineVar als "Str"-Argument, nicht als Ptr/Adresse; 2) [v1.0.44.03+]: Rufen Sie VarSetCapacity(MeineVar, -1) auf, um die intern gespeicherte Länge der Variable nach dem Aufruf von DllCall zu aktualisieren.

Eine binäre Null, die von einer Funktion in einer Variable hinterlegt wurde, versteckt alle Daten rechts von der Null, d.h. die meisten Befehle und Funktionen können diese Daten weder lesen noch verändern. Allerdings können solche Daten mit dem Adressoperator und NumPut()/NumGet() oder mit DllCall selbst manipuliert werden.

Eine Funktion, die die Adresse einer der ihr übergebenen Zeichenketten zurückgibt, kann eine identische Zeichenkette zurückgeben, die auf einer anderen Speicheradresse liegt als erwartet. Zum Beispiel würde der Aufruf von CharLower(CharUpper(MeineVar)) in einer anderen Programmiersprache bewirken, dass der Inhalt von MeineVar in Kleinbuchstaben umgewandelt wird. Aber wenn dasselbe mit DllCall() gemacht wird, wäre MeineVar nach dem folgenden Aufruf in Großbuchstaben, weil CharLower mit einer anderen/temporären Zeichenkette gearbeitet hat, die mit MeineVar identisch ist:

MeineVar := "ABC"
Ergebnis := DllCall("CharLower", "Str", DllCall("CharUpper", "Str", MeineVar, "Str"), "Str")

Um das zu umgehen, ersetzen Sie oben die zwei unterstrichenen "Str"-Werte mit Ptr. Dadurch wird sichergestellt, dass der Rückgabewert von CharUpper als reine Adresse interpretiert wird, die dann als Integer an CharLower übergeben wird.

Beim Umgang mit Zeichenketten kann es zu Einschränkungen kommen. Weitere Informationen finden Sie unter Skriptkompatibilität.

Component Object Model (COM)

COM-Objekte, auf die VBScript und ähnliche Programmiersprachen zugreifen können, sind in der Regel auch für AutoHotkey über ComObjCreate(), ComObjGet() oder ComObjActive() und die interne Objektsyntax zugänglich.

COM-Objekte, die IDispatch nicht unterstützen, können mit DllCall verwendet werden, indem die Adresse einer Funktion aus der virtuellen Funktionstabelle des Objekt-Interfaces ermittelt wird. Weitere Informationen finden Sie im Beispiel weiter unten.

.NET Framework

.NET Framework-Bibliotheken werden von einer "virtuellen Maschine" ausgeführt, die als Common Language Runtime (CLR) bekannt ist. In diesem Fall sind .NET-DLL-Dateien anders formatiert als normale DLL-Dateien und enthalten in der Regel keine Funktionen, die von DllCall aufgerufen werden können.

AutoHotkey kann jedoch die CLR über COM Callable Wrapper nutzen. Sofern die Bibliothek nicht auch als allgemeine COM-Komponente registriert ist, muss die CLR selbst zunächst manuell über DllCall initialisiert werden. Weitere Informationen finden Sie unter .NET Framework Interop.

Skriptkompatibilität, PostMessage, OnMessage(), RegisterCallback(), Run, VarSetCapacity(), Funktionen, SysGet, Microsoft Docs

Beispiele

Ruft die Windows-API-Funktion "MessageBox" auf und meldet, welche Schaltfläche der Benutzer gedrückt hat.

WelcheSchaltfl := DllCall("MessageBox", "Int", 0, "Str", "Ja oder Nein drücken", "Str", "Titel der Box", "Int", 4)
MsgBox Sie haben die Schaltfläche Nr. %WelcheSchaltfl% gedrückt.

Ersetzt das Hintergrundbild des Desktops mit der angegebenen Bitmap-Datei (.bmp).

DllCall("SystemParametersInfo", "UInt", 0x14, "UInt", 0, "Str", A_WinDir . "\winnt.bmp", "UInt", 1)

Ruft die API-Funktion "IsWindowVisible" auf, um herauszufinden, ob ein Notepad-Fenster sichtbar ist.

DetectHiddenWindows On
if not DllCall("IsWindowVisible", "Ptr", WinExist("Unbenannt - Editor"))  ; WinExist() gibt eine HWND-Nummer zurück.
    MsgBox Das Fenster ist nicht sichtbar.

Ruft die API-Funktion wsprintf() auf, um die linke Seite der Zahl 432 mit Nullen zu füllen, bis sie 10 Zeichen breit ist (0000000432).

VarSetCapacity(AufgefüllteZahl, 20)  ; Stellt sicher, dass die Variable groß genug für die neue Zeichenkette ist.
DllCall("wsprintf", "Str", AufgefüllteZahl, "Str", "%010d", "Int", 432, "Cdecl")  ; Benötigt die Cdecl-Aufrufkonvention.
MsgBox %AufgefüllteZahl%

; [v1.1.17+]: Dasselbe kann mit der Format-Funktion in Verbindung mit dem Null-Flag erreicht werden:
MsgBox % Format("{:010}", 432)

Zeigt, wie mit QueryPerformanceCounter() eine höhere Präzision als die 10 ms von A_TickCount erreicht werden kann.

DllCall("QueryPerformanceFrequency", "Int64*", freq)
DllCall("QueryPerformanceCounter", "Int64*", CounterDavor)
Sleep 1000
DllCall("QueryPerformanceCounter", "Int64*", CounterDanach)
MsgBox % "Die Differenz zwischen den Zeiten beträgt " . (CounterDanach - CounterDavor) / freq * 1000 " ms"

Drücken Sie einen Hotkey, um die Geschwindigkeit des Mauszeigers vorübergehend zu verringern, was eine genauere Positionierung ermöglicht. Halten Sie F1 gedrückt, um den Mauszeiger zu verlangsamen. Lassen Sie die Taste wieder los, um die originale Geschwindigkeit wiederherzustellen.

F1::
SPI_GETMOUSESPEED := 0x70
SPI_SETMOUSESPEED := 0x71
; Ruft die aktuelle Geschwindigkeit ab, um sie später wiederherzustellen:
DllCall("SystemParametersInfo", "UInt", SPI_GETMOUSESPEED, "UInt", 0, "UIntP", OrigMausGeschw, "UInt", 0)
; Verringert nun die Geschwindigkeit des Mauszeigers im vorletzten Parameter (im Bereich von 1 bis 20, 10 ist Standard):
DllCall("SystemParametersInfo", "UInt", SPI_SETMOUSESPEED, "UInt", 0, "Ptr", 3, "UInt", 0)
KeyWait F1  ; Verhindert, dass DllCall durch die Autowiederholung der Tastatur wiederholt aufgerufen wird.
return

F1 up::DllCall("SystemParametersInfo", "UInt", SPI_SETMOUSESPEED, "UInt", 0, "Ptr", OrigMausGeschw, "UInt", 0)  ; Stellt die Originalgeschwindigkeit wieder her.

Überwacht das aktive Fenster und zeigt die Position des vertikalen Scrollbalkens seines fokussierten Steuerelements an (in Echtzeit). Dieses Beispiel benötigt [v1.0.43.06+], weil es ControlGet Hwnd verwendet.

#Persistent
SetTimer, ScrollbalkenÜberwachen, 100
return

ScrollbalkenÜberwachen:
AktivesFenster := WinExist("A")
if not AktivesFenster  ; Kein Fenster aktiv.
    return
ControlGetFocus, FokussiertesStrlmnt, ahk_id %AktivesFenster%
if not FokussiertesStrlmnt  ; Kein Steuerelement fokussiert.
    return
; Vertikale oder horizontale Position des Scrollbalkens in einem Tooltip anzeigen:
ControlGet, UnterelementHWND, Hwnd,, %FokussiertesStrlmnt%, ahk_id %AktivesFenster%
ToolTip % DllCall("GetScrollPos", "Ptr", UnterelementHWND, "Int", 1)  ;  Letzter Parameter kann 1 für SB_VERT und 0 für SB_HORZ sein.
return

Schreibt etwas Text in eine Datei und liest ihn zurück in den Speicher (benötigt [v1.0.34+]). Diese Methode ist performanter, wenn es darum geht, mehrere Dateien simultan zu lesen oder zu schreiben. [AHK_L 42+]: Dasselbe kann mit FileOpen() erreicht werden. Siehe entsprechendes Beispiel.

FileSelectFile, DateiName, S16,, Neue Datei erstellen:
if (DateiName = "")
    return
GENERIC_WRITE := 0x40000000  ; Öffnet eine Datei zum Schreiben statt zum Lesen.
CREATE_ALWAYS := 2  ; Erstellt eine neue Datei (überschreibt eine vorhandene Datei).
hFile := DllCall("CreateFile", "Str", DateiName, "UInt", GENERIC_WRITE, "UInt", 0, "Ptr", 0, "UInt", CREATE_ALWAYS, "UInt", 0, "Ptr", 0, "Ptr")
if not hFile
{
    MsgBox Kann "%DateiName%" nicht zum Schreiben öffnen.
    return
}
TestZkette := "Das ist eine Zeichenkette.`r`n"  ; Wenn eine Datei auf diese Weise geschrieben wird, sollte `r`n anstelle von `n verwendet werden, um eine neue Zeile zu beginnen.
ZketteLänge := StrLen(TestZkette) * (A_IsUnicode ? 2 : 1)
DllCall("WriteFile", "Ptr", hFile, "Str", TestZkette, "UInt", ZketteLänge, "UIntP", RealGeschriebeneBytes, "Ptr", 0)
DllCall("CloseHandle", "Ptr", hFile)  ; Schließt die Datei.

; Die Datei wurde geschrieben, also lese ihren Inhalt zurück in den Speicher.
GENERIC_READ := 0x80000000  ; Öffnet die Datei zum Lesen statt zum Schreiben.
OPEN_EXISTING := 3  ; Dieser Modus bewirkt, dass die zu öffnende Datei bereits existieren muss.
FILE_SHARE_READ := 0x1 ; Dieser und der nächste Modus bestimmen, ob andere Prozesse die bereits geöffnete Datei öffnen dürfen.
FILE_SHARE_WRITE := 0x2
hFile := DllCall("CreateFile", "Str", DateiName, "UInt", GENERIC_READ, "UInt", FILE_SHARE_READ|FILE_SHARE_WRITE, "Ptr", 0, "UInt", OPEN_EXISTING, "UInt", 0, "Ptr", 0)
if not hFile
{
    MsgBox Kann "%DateiName%" nicht zum Lesen öffnen.
    return
}
; Macht die Variable aus Testgründen leer, stellt aber sicher, dass sie genügend Kapazität hat:
ZuLesendeBytes := VarSetCapacity(TestZkette, ZketteLänge)
DllCall("ReadFile", "Ptr", hFile, "Str", TestZkette, "UInt", ZuLesendeBytes, "UIntP", RealGeleseneBytes, "Ptr", 0)
DllCall("CloseHandle", "Ptr", hFile)  ; Schließt die Datei.
MsgBox Die folgende Zeichenkette wurde aus der Datei gelesen: %TestZkette%

Versteckt den Mauszeiger, wenn Sie WIN+C drücken. Um den Mauszeiger wieder sichtbar zu machen, drücken Sie diesen Hotkey erneut. Dieses Skript stammt von www.autohotkey.com/forum/topic6107.html

OnExit, ZeigeCursor  ; Stellt sicher, dass der Mauszeiger bei Beendigung des Skripts wieder sichtbar gemacht wird.
return

ZeigeCursor:
SystemCursor("On")
ExitApp

#c::SystemCursor("Toggle")  ; WIN+C-Hotkey zum Ein- und Ausschalten des Mauszeigers.

SystemCursor(OnOff=1)   ; INIT = "I","Init"; OFF = 0,"Off"; TOGGLE = -1,"T","Toggle"; ON = Andere
{
    static AndMask, XorMask, $, h_cursor
        ,c0,c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11,c12,c13 ; System-Mauszeiger
        , b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13   ; Leere Mauszeiger
        , h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11,h12,h13   ; Handles von Standardzeigern
    if (OnOff = "Init" or OnOff = "I" or $ = "")       ; Initialisierung bei Bedarf oder beim ersten Aufruf
    {
        $ := "h"                                       ; Aktive Standardzeiger
        VarSetCapacity( h_cursor,4444, 1 )
        VarSetCapacity( AndMask, 32*4, 0xFF )
        VarSetCapacity( XorMask, 32*4, 0 )
        system_cursors := "32512,32513,32514,32515,32516,32642,32643,32644,32645,32646,32648,32649,32650"
        StringSplit c, system_cursors, `,
        Loop %c0%
        {
            h_cursor   := DllCall( "LoadCursor", "Ptr",0, "Ptr",c%A_Index% )
            h%A_Index% := DllCall( "CopyImage", "Ptr",h_cursor, "UInt",2, "Int",0, "Int",0, "UInt",0 )
            b%A_Index% := DllCall( "CreateCursor", "Ptr",0, "Int",0, "Int",0
                , "Int",32, "Int",32, "Ptr",&AndMask, "Ptr",&XorMask )
        }
    }
    if (OnOff = 0 or OnOff = "Off" or $ = "h" and (OnOff < 0 or OnOff = "Toggle" or OnOff = "T"))
        $ := "b"  ; Leere Mauszeiger nutzen
    else
        $ := "h"  ; Gespeicherte Mauszeiger nutzen

    Loop %c0%
    {
        h_cursor := DllCall( "CopyImage", "Ptr",%$%%A_Index%, "UInt",2, "Int",0, "Int",0, "UInt",0 )
        DllCall( "SetSystemCursor", "Ptr",h_cursor, "UInt",c%A_Index% )
    }
}

Strukturbeispiel. Übergibt die Adresse einer RECT-Struktur an die GetWindowRect-Funktion, die die Struktur mit den Koordinaten der linken oberen und der rechten unteren Ecke des Fensters füllt (relativ zum Bildschirm).

Run Notepad
WinWait Unbenannt - Editor  ; Setzt auch das "zuletzt gefundene Fenster" für WinExist() unten.
VarSetCapacity(Rect, 16)  ; RECT ist eine Struktur bestehend aus vier 32-Bit-Integern (also 4*4=16).
DllCall("GetWindowRect", "Ptr", WinExist(), "Ptr", &Rect)  ; WinExist() gibt eine HWND-Nummer zurück.
MsgBox % "Links " . NumGet(Rect, 0, "Int") . " Oben " . NumGet(Rect, 4, "Int")
    . " Rechts " . NumGet(Rect, 8, "Int") . " Unten " . NumGet(Rect, 12, "Int")

Strukturbeispiel. Übergibt FillRect() die Adresse einer RECT-Struktur, die einen Bereich des Bildschirms definiert, der kurzzeitig rot gefärbt werden soll.

VarSetCapacity(Rect, 16, 0)  ; Setzt die Kapazität zum Speichern von vier 4-Byte-Integern und initialisiert sie alle mit Null.
NumPut(A_ScreenWidth//2, Rect, 8, "Int")  ; Der dritte Integer in der Struktur ist "rect.right".
NumPut(A_ScreenHeight//2, Rect, 12, "Int") ; Der vierte Integer in der Struktur ist "rect.bottom".
hDC := DllCall("GetDC", "Ptr", 0, "Ptr")  ; Übergibt Null, um den Gerätekontext des Desktops abzurufen.
hBrush := DllCall("CreateSolidBrush", "UInt", 0x0000FF, "Ptr")  ; Erstellt einen roten Pinsel (0x0000FF ist im BGR-Format).
DllCall("FillRect", "Ptr", hDC, "Ptr", &Rect, "Ptr", hBrush)  ; Färbt das angegebene Rechteck mit dem obigen Pinsel.
DllCall("ReleaseDC", "Ptr", 0, "Ptr", hDC)  ; Gibt Speicher frei.
DllCall("DeleteObject", "Ptr", hBrush)  ; Gibt Speicher frei.

Strukturbeispiel. Setzt die Systemuhr auf ein bestimmtes Datum und eine bestimmte Uhrzeit. Seien Sie vorsichtig, wenn Sie ein zukünftiges Datum setzen, da dies dazu führen kann, dass geplante Tasks vorzeitig ausgeführt werden!

SetzeSystemuhr("20051008142211")  ; Übergeben Sie einen Zeitstempel (lokal, nicht UTC).

SetzeSystemuhr(YYYYMMDDHHMISS)
; Setzt die Systemuhr auf ein bestimmtes Datum und eine bestimmte Uhrzeit.
; Der Aufrufer muss sicherstellen, dass der eingehende Parameter ein gültiger Zeitstempel ist
; (Ortszeit, nicht UTC). Gibt bei Erfolg ungleich 0 zurück.
{
    ; Konvertiert die im Parameter angegebene Ortszeit in UTC für SetSystemTime().
    UTC_Delta -= A_NowUTC, Seconds  ; Sekunden sind genauer, um Rundungsfehler zu vermeiden.
    UTC_Delta := Round(-UTC_Delta/60)  ; Rundet auf die nächste Minute für höhere Genauigkeit.
    YYYYMMDDHHMISS += UTC_Delta, Minutes  ; Wendet den Offset für die Konvertierung zu UTC an.

    VarSetCapacity(Systemuhr, 16, 0)  ; Diese Struktur besteht aus 8 UShorts (also 8*2=16).

    Int := SubStr(YYYYMMDDHHMISS, 1, 4)  ; YYYY (Jahr)
    NumPut(Int, Systemuhr, 0, "UShort")
    Int := SubStr(YYYYMMDDHHMISS, 5, 2)  ; MM (Monat des Jahres, 1-12)
    NumPut(Int, Systemuhr, 2, "UShort")
    Int := SubStr(YYYYMMDDHHMISS, 7, 2)  ; DD (Tag des Monats)
    NumPut(Int, Systemuhr, 6, "UShort")
    Int := SubStr(YYYYMMDDHHMISS, 9, 2)  ; HH (Stunden im 24-Stunden-Format)
    NumPut(Int, Systemuhr, 8, "UShort")
    Int := SubStr(YYYYMMDDHHMISS, 11, 2) ; MI (Minuten)
    NumPut(Int, Systemuhr, 10, "UShort")
    Int := SubStr(YYYYMMDDHHMISS, 13, 2) ; SS (Sekunden)
    NumPut(Int, Systemuhr, 12, "UShort")

    return DllCall("SetSystemTime", "Ptr", &Systemuhr)
}

Weitere Strukturbeispiele:

Entfernt mittels COM das aktive Fenster temporär aus der Taskleiste.

/*
  Methoden in der ITaskbarList-VTable:
    IUnknown:
      0 QueryInterface  -- nutze stattdessen ComObjQuery()
      1 AddRef          -- nutze stattdessen ObjAddRef()
      2 Release         -- nutze stattdessen ObjRelease()
    ITaskbarList:
      3 HrInit
      4 AddTab
      5 DeleteTab
      6 ActivateTab
      7 SetActiveAlt
*/
IID_ITaskbarList  := "{56FDF342-FD6D-11d0-958A-006097C9A090}"
CLSID_TaskbarList := "{56FDF344-FD6D-11d0-958A-006097C9A090}"

; Erstellt ein TaskbarList-Objekt und speichert dessen Adresse in tbl.
tbl := ComObjCreate(CLSID_TaskbarList, IID_ITaskbarList)

activeHwnd := WinExist("A")

DllCall(vtable(tbl,3), "ptr", tbl)                     ; tbl.HrInit()
DllCall(vtable(tbl,5), "ptr", tbl, "ptr", activeHwnd)  ; tbl.DeleteTab(activeHwnd)
Sleep 3000
DllCall(vtable(tbl,4), "ptr", tbl, "ptr", activeHwnd)  ; tbl.AddTab(activeHwnd)

; Nicht-Dispatch-Objekte müssen immer manuell freigegeben werden.
ObjRelease(tbl)

vtable(ptr, n) {
    ; NumGet(ptr+0) gibt die Adresse der virtuellen Funktionstabelle
    ; des Objekts (kurz: vtable) zurück. Der Rest des Ausdrucks ruft
    ; die Adresse der n-ten Funktionsadresse aus der vtable ab.
    return NumGet(NumGet(ptr+0), n*A_PtrSize)
}