DllCall()

Ruft eine Funktion aus einer DLL-Datei auf, wie 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" (lässt man die Dateiendung weg, 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. 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" das gleiche Ergebnis wie "IsWindowVisible".

Wenn keine Funktion unter dem angegebenen Namen gefunden werden kann, 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" in ANSI-Versionen das gleiche wie "MessageBoxA" und in Unicode-Versionen das gleiche wie "MessageBoxW".

Wenn die DLL wiederholt aufgerufen wird, ist es ratsam, diese im Voraus zu laden, um eine deutliche Erhöhung der Leistung zu erzielen.

[v1.0.46.08+]: Dieser Parameter kann auch ein reiner Integer sein, der als Adresse der aufzurufenden Funktion interpretiert wird. Quellen solcher Adressen sind unter anderem 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 unteren Typentabelle 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 eher die Standardaufrufkonvention als die C-Aufrufkonvention verwenden (Funktionen wie wsprintf, die eine unterschiedliche Anzahl von Argumenten akzeptieren, sind so eine Ausnahme). Wenn Cdecl weggelassen wird, aber der Aufruf ErrorLevel An liefert -- hierbei ist n die Gesamtgröße der übergebenen Argumente -- muss Cdecl eventuell angegeben werden. Beachten Sie, dass die meisten objektorientierten C++-Funktionen die thiscall-Konvention nutzen, die in AutoHotkey nicht unterstützt wird.

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

[AHK_L 53+]: Da eine separate C-Aufrufkonvention im 64-Bit-Code nicht existiert, ist die Angabe von Cdecl in 64-Bit-Versionen von AutoHotkey wirkungslos.

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

Rückgabewert

DllCall gibt den aktuellen 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 das Ergebnis 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. Der folgende Aufruf wandelt z. B. den Inhalt von MeineVar in Großbuchstaben um: DllCall("CharUpper", "Str", MeineVar).

Wenn die Funktion jedoch eine Zeichenkette zurückgibt, die größer als die aktuelle Kapazität einer Variable ist, sollten Sie vor dem Funktionsaufruf sicherstellen, dass diese Variable groß genug ist. Um das zu erreichen, können Sie VarSetCapacity(MeineVar, 123) aufrufen. Ersetzen Sie 123 mit der gewünschten Kapazität, die MeineVar haben soll.

Ein Str-Argument darf kein Ausdruck sein, der zu einer Zahl ausgewertet wird (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 in der Regel nicht benötigt. Dies kann in Verbindung mit Funktionen genutzt 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 Skript-Kompatibilität.
Int64 Ein 64-Bit-Integer im Bereich von -9223372036854775808 (-0x8000000000000000) bis 9223372036854775807 (0x7FFFFFFFFFFFFFFF).
Int

Ein 32-Bit-Integer (der am häufigsten verwendete Integer-Typ) 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 Nachkommastellen.
Double Eine 64-Bit-Floating-Point-Zahl mit einer Genauigkeit von 15 Nachkommastellen.
Ptr

[AHK_L 42+]: Ein pointergroßer Integer, der je nach AutoHotkey-Version (32- oder 64-Bit) einem Int oder Int64 entspricht. 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 wie LPDWORD oder int* verweist, sollte grundsätzlich das *- oder P-Suffix anstelle von "Ptr" verwendet werden.

Ptr kann auch mit dem *- oder P-Suffix kombiniert werden; allerdings sollte dies nur bei Funktionen verwendet werden, die einen Pointer über LPVOID* oder ähnlichem zurückgeben.

UPtr ist ebenfalls gültig, aber nur in 32-Bit-Versionen vorzeichenlos, da AutoHotkey keine vorzeichenlose 64-Bit-Integer unterstützt.

Wenn das Skript mit älteren Versionen von AutoHotkey kompatibel sein muss, können Sie einen Variablentyp wie folgt nutzen:

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 einen 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 oben genannten Typen an, um nicht den Wert, sondern die Adresse des Arguments zu übergeben (die aufgerufene Funktion muss damit umgehen können). Der Wert von so einem Argument kann von der Funktion geändert werden; das heißt, dass, wenn eine reine Variable als Argument übergeben wurde, der Inhalt dieser Variable aktualisiert wird. Der folgende Aufruf beispielsweise übergibt den Inhalt von MeineVar an MeineFunktion via Adresse, aber aktualisiert auch den Inhalt von MeineVar, um alle Änderungen, die MeineFunktion an MeineVar durchgeführt hat, widerzuspiegeln: DllCall("MeineDLL\MeineFunktion", "Int*", MeineVar).

In der Regel nutzt man ein Sternchen, wenn ein Argument- oder Rückgabetyp mit "LP" beginnt. Das bekannteste Beispiel dafür ist LPDWORD (ein Pointer, der auf ein DWORD verweist). DWORD ist ein vorzeichenloser 32-Bit-Integer, demzufolge muss für LPDWORD "UInt*" oder "UIntP" verwendet werden. Zeichenkettentypen wie LPTSTR, auf Strukturen verweisende Pointer wie LPRECT, oder Arrays sollten nicht mit einem Sternchen versehen werden; für solche Typen ist "Str" oder "Ptr" besser geeignet, je nachdem, ob eine Variable oder Adresse übergeben wird.

Hinweis: "Char*" ist nicht das gleiche 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) groß ist. So ä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 Bits erwarten.

Da Variablen in AutoHotkey keinen festen Typ haben, bezieht sich 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, weil DllCall diese Variable nach dem Funktionsaufruf korrekt aktualisieren wird.

U (Präfix)

Fügen Sie an einen der oben genannten Integer-Typen den Buchstaben U an, um den entsprechenden Wert als vorzeichenlosen Integer (UInt64, Uint, UShort und UChar) zu behandeln. Streng genommen ist das nur für Rückgabewerte und Sternchenvariablen notwendig, da es keine Rolle spielt, ob das via Wert übergebene 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. Wenn zum Beispiel -1 als UInt gesendet wird, wird es zu 0xFFFFFFFF.

Vorzeichenlose 64-Bit-Integer, die von einer Funktion erzeugt werden, werden nicht unterstützt. Um mit Zahlen größer gleich 0x8000000000000000 umzugehen, sollten Sie auf das U-Präfix verzichten und alle von der Funktion kommenden negativen Werte als große Integer (Int64) behandeln. Wenn eine Funktion zum Beispiel -1 als UInt64 zurückgibt und dieser Rückgabewert als Int64 behandelt wird, erhält man 0xFFFFFFFFFFFFFFFF.

Für Parameter vom Typ UInt64 können lange vorzeichenlose Werte als Zeichenketten übergeben werden. Für kleinere Integer-Typen 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 genutzt wird. Allerdings kann es nicht schaden, für Werte, die normalerweise vorzeichenlos sind, das U-Präfix zu verwenden, um die Übersichtlichkeit zu verbessern.

Veraltet: Die Anführungszeichen können bei den Argument- oder Rückgabetypen weggelassen werden, sofern keine Leerzeichen oder Sternchen enthalten sind. Zum Beispiel kann Str anstelle von "Str" und CDecl anstelle von "CDecl" verwendet werden. Diese Vorgehensweise 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 hervorgerufen werden, wenn ein Ausdruck, der zu einer Zahl ausgewertet wird, an ein Zeichenkettenargument (Str) übergeben wird.

-3: Die angegebene DllDatei konnte weder zugegriffen noch 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 für die Datei hat, oder wenn AutoHotkey im 32-Bit-Format und die DLL im 64-Bit-Format ist (oder umgekehrt).

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

N (beliebige positive Nummer): Die Funktion wurde aufgerufen, aber mit der fatalen Ausnahme Nummer N abgebrochen (0xC0000005 bedeutet z. B. "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 nie den im nächsten Abschnitt erwähnten "An"-Fehler erzeugt, löst die Funktion stattdessen eine Ausnahme aus, wenn ihr zu wenig Argumente übergeben werden.

An (Buchstabe A, gefolgt von einem Integer n): Der Aufruf der Funktion war erfolgreich, allerdings 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, damit die Funktion problemlos ausgeführt werden kann. Dieser Fehler könnte 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-Versionen von AutoHotkey aufgrund der x64-Aufrufkonvention nicht in der Lage sind, ErrorLevel auf An zusetzen.

Ausnahmen und A_LastError

Trotz der internen Ausnahmebehandlung ist es immer noch möglich, ein Skript mit DllCall zum Absturz zu bringen. Dies kann passieren, wenn eine Funktion etwas Unangebrachtes zurückgibt, wie z. B. einen fehlerhaften Pointer oder eine nicht-terminierte Zeichenkette, statt eine Ausnahme auszulösen. Die Ursache dafür muss nicht immer die Funktion selbst sein. Auch das Skript könnte ihr einen ungeeigneten Wert (z. B. einen fehlerhaften Pointer oder ein "Str" mit unzureichender Kapazität) übergeben. Ein Skript kann auch abstürzen, wenn ein falscher Argument- oder Rückgabetyp angegeben ist, z. B. mit der Behauptung, dass der Rückgabewert einer Funktion eine Sternchenvariable oder Str ist, obwohl es in Wirklichkeit ein gewöhnlicher Integer ist.

Die interne Variable A_LastError enthält den Rückgabewert der Systemfunktion GetLastError(), die sofort nach einem Funktionsaufruf aufgerufen wird (dies hat keine messbaren Auswirkungen auf die Leistung). A_LastError ist eine Nummer zwischen 0 und 4294967295 (immer in dezimaler Form, nicht hexadezimal). A_LastError ist wie ErrorLevel eine Pro-Thread-Einstellung; das sind Einstellungen, die nicht von anderen Threads geändert werden können. Allerdings wird A_LastError auch von Run/RunWait gesetzt.

Leistung

Wenn die DLL wiederholt aufgerufen wird, ist es ratsam, diese im Voraus zu laden, um eine deutliche Erhöhung der Leistung zu erzielen (das ist für eine Standard-DLL wie User32 nicht notwendig, da sie immer im Speicher vorhanden ist). Diese Vorgehensweise verhindert, dass DllCall jedes Mal intern LoadLibrary und FreeLibrary 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 ihrer Benutzung wieder freigegeben werden.

[v1.0.46.08+]: Um eine noch schnellere Leistung zu erzielen, können Sie im Voraus die Adresse der Funktion ermitteln. 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 vor dem Skriptstart normal geladen wird, wird die Zeichenkette automatisch in eine Funktionsadresse aufgelöst. Diese interne Optimierung ist effektiver als das oben gezeigte Beispiel.

Des Weiteren können Sie #NoEnv in Ihr Skript einfügen, um die Leistung von DllCalls zu verbessern, die anführungszeichenlose Parametertypen verwenden (z. B. Int statt "Int").

Die Leistung von DllCall kann zudem verbessert werden, wenn eine Zeichenkettenvariable nicht als "str", sondern via Adresse (z. B. &MeineVar) an eine Funktion übergeben wird (besonders wenn die Zeichenkette sehr lang ist); dies setzt aber voraus, dass die Länge der Zeichenkette nicht von der Funktion geändert wird. Das folgende Beispiel wandelt eine 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, wenn die binären Rohdaten der Struktur in eine normale Variable gespeichert werden. Es sind folgende Schritte dafür notwendig:

1) Rufen Sie VarSetCapacity(MeineStrukt, 123, 0) auf, um sicherzustellen, dass die Kapazität der Zielvariable groß genug für die Struktur ist. Geben Sie für 123 die Größe der Struktur oder höher an. Die 0 im letzten Parameter ist optional und bewirkt, dass alle Strukturelemente mit einer binären Null initialisiert werden, um ein häufiges Aufrufen von NumPut() wie im nächsten Schritt beschrieben zu verhindern.

2) Wenn die Zielfunktion bereits beim Aufrufen bestimmte Werte in der Struktur benötigt, können Sie NumPut(123, MeineStrukt, 4, "UInt") verwenden, um ein Element auf einen bestimmten Wert zu setzen. Geben Sie für 123 den Integer an, der in das Strukturelement eingefügt werden soll (oder nutzen Sie &Var, um die Adresse einer Variable zu speichern). Geben Sie für 4 den Offset des Strukturelements an (siehe Schritt #4, was ein "Offset" ist). Geben Sie für "UInt" den entsprechenden Typ an oder lassen Sie den Parameter weg, wenn das Strukturelement ein Pointer oder Handle ist.

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

4) Verwenden Sie MeinInteger := NumGet(MeineStrukt, 4, "UInt"), um den Integer eines Strukturelements abzurufen. Geben Sie für 4 den Offset des Elements innerhalb der Struktur an. Das erste Element liegt immer auf Offset 0. Das zweite Element liegt auf Offset 0 plus der Größe des ersten Elements (in der Regel 4). Jedes Element, das danach erfolgt, liegt 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. Geben Sie für "UInt" den entsprechenden Typ an oder lassen Sie den Parameter weg, wenn das Element ein Pointer oder Handle ist.

Strukturbeispiele finden Sie im Beispielabschnitt weiter unten.

Bekannte Einschränkungen

Wenn eine Variable via Adresse (z. B. &MeineVar) an eine Funktion übergeben und ihre Länge von dieser Funktion geändert wird, kann es passieren, dass diese Variable bei späterem Gebrauch ein fehlerhaftes Verhalten aufweist. Um dies zu verhindern, gibt es folgende Lösungsmöglichkeiten: 1) Übergeben Sie MeineVar nicht als Ptr/Adresse, sondern als "Str"-Argument; 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 innerhalb einer Variable führt dazu, dass alle rechts befindlichen Daten versteckt werden; das heißt, dass solche Daten von den meisten Befehlen und Funktionen weder abgerufen noch geändert werden können. Solche Daten können aber mit dem Adressoperator und NumPut()/NumGet() oder mit DllCall selbst manipuliert werden.

Es ist möglich, dass eine Funktion, die die Adresse einer zuvor erhaltenen Zeichenkette zurückgibt, dieselbe Zeichenkette ungewollt auf einer anderen Speicheradresse zurückgibt. CharLower(CharUpper(MeineVar)) beispielsweise würde bei einer Programmiersprache wie C++ bewirken, dass der Inhalt von MeineVar in Kleinbuchstaben umgewandelt wird. Nutzt man stattdessen DllCall() wie unten gezeigt, bleibt der Inhalt von MeineVar groß geschrieben, weil CharLower eine andere/temporäre Zeichenkette verarbeitet hat, die identisch zum Inhalt von MeineVar ist:

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

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

Beim Umgang mit Zeichenketten können bestimmte Einschränkungen auftreten. Weitere Informationen finden Sie unter Skript-Kompatibilität.

Component Object Model (COM)

COM-Objekte, die für VBScript und ähnliche Sprachen zugänglich sind, können in der Regel via ComObjCreate(), ComObjGet() oder ComObjActive() in Kombination mit der internen Objektsyntax angesteuert werden.

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

Der Großteil des .NET-Frameworks kann auch via COM und DllCall angesteuert werden. Weitere Informationen finden Sie unter .NET Framework Interop (englisch).

Skript-Kompatibilitä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 drückt.

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

Ersetzt das Desktop-Hintergrundbild 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 Fenster des Texteditors 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 Zahl 432 auf der linken Seite mit Nullen aufzufüllen, bis sie eine Breite von 10 Zeichen hat (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+]: Das gleiche kann via Format-Funktion in Verbindung mit dem Null-Flag erreicht werden:
MsgBox % Format("{:010}", 432)

Demonstriert, wie man mit QueryPerformanceCounter() eine höhere Präzision als die 10 ms von A_TickCount erreichen 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 diese Taste wieder los, um die originale Geschwindigkeit wiederherzustellen.

F1::
SPI_GETMOUSESPEED := 0x70
SPI_SETMOUSESPEED := 0x71
; Ermittelt die aktuelle Geschwindigkeit, 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 das Auto-Wiederholungs-Feature der Tastatur DllCall wiederholt aufruft.
return

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

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

#Persistent
SetTimer, ScrollleisteÜberwachen, 100
return

ScrollleisteÜberwachen:
AktivesFenster := WinExist("A")
if not AktivesFenster  ; Kein aktives Fenster.
    return
ControlGetFocus, FokussiertesStrlmnt, ahk_id %AktivesFenster%
if not FokussiertesStrlmnt  ; Kein fokussiertes Steuerelement.
    return
; Zeigt die vertikale oder horizontale Position der Scrollleiste in einem Tooltip an:
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 kann genutzt werden, um die Performance beim gleichzeitigen Lesen oder Schreiben mehrerer Dateien zu verbessern. [AHK_L 42+]: Das gleiche kann mit FileOpen() erreicht werden. Siehe dazu das Beispiel.

FileSelectFile, DateiName, S16,, Neue Datei erstellen:
if (DateiName = "")
    return
GENERIC_WRITE := 0x40000000  ; Öffnet eine Datei zum Schreiben.
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.

; Liest den Inhalt der Datei, nachdem sie geschrieben wurde, zurück in den Speicher.
GENERIC_READ := 0x80000000  ; Öffnet die Datei zum Lesen.
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 können.
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, aber stellt sicher, dass sie genügend Kapazität zur Verfügung 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 erneut diesen Hotkey. Dieses Skript stammt von www.autohotkey.com/forum/topic6107.html

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

ZeigeCursor:
SystemCursor("On")
ExitApp

#c::SystemCursor("Toggle")  ; Drückt man WIN+C, wird der Mauszeiger jeweils ein- oder ausgeschaltet.

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 ; Mauszeiger vom System
        , 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 benutzen
    else
        $ := "h"  ; Gespeicherte Mauszeiger benutzen

    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% )
    }
}

Struktur-Beispiel. Übergibt die Adresse einer RECT-Struktur an die GetWindowRect-Funktion, die die Strukturelemente auf die Positionen der linken, oberen, rechten und unteren Seite des Fensters setzt (relativ zum Bildschirm).

Run Notepad
WinWait Unbenannt - Editor  ; Setzt auch das "zuletzt gefundene Fenster" für das untere WinExist().
VarSetCapacity(Rect, 16)  ; RECT ist eine Struktur, die aus vier 32-Bit-Integern besteht (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")

Struktur-Beispiel. Übergibt an FillRect() die Adresse einer RECT-Struktur, die einen Bereich des Bildschirms kennzeichnet, 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üllt das angegebene Rechteck mit dem Pinsel von oben.
DllCall("ReleaseDC", "Ptr", 0, "Ptr", hDC)  ; Gibt Speicher frei.
DllCall("DeleteObject", "Ptr", hBrush)  ; Gibt Speicher frei.

Struktur-Beispiel. Stellt die Systemuhr auf ein bestimmtes Datum und eine bestimmte Uhrzeit um. 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)
; Stellt die Systemuhr auf ein bestimmtes Datum und eine bestimmte Uhrzeit um.
; Der Aufrufer muss sicherstellen, dass der eingehende Parameter ein gültiger Zeitstempel ist
; (lokale Zeit, nicht UTC). Übergibt bei Erfolg ungleich 0 zurück.
{
    ; Konvertiert die im Parameter angegebene lokale Zeit in UTC, damit sie in Verbindung mit SetSystemTime() genutzt werden kann.
    UTC_Delta -= A_NowUTC, Seconds  ; Sekunden sind genauer, um Rundungsfehler zu umgehen.
    UTC_Delta := Round(-UTC_Delta/60)  ; Rundet auf die nächste Minute, um Genauigkeit zu gewährleisten.
    YYYYMMDDHHMISS += UTC_Delta, Minutes  ; Wendet den Offset für die Konvertierung zu UTC an.

    VarSetCapacity(Systemuhr, 16, 0)  ; Diese Struktur besteht aus 8 UShort-Werten (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 Struktur-Beispiele:

Entfernt mithilfe von COM vorübergehend das aktive Fenster 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 seine 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)
}