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

Ergebnis

DllCall gibt den aktuellen Rückgabewert der Funktion zurück. Unterstützt die Funktion keinen Rückgabewert, übergibt sie einen undefinierten Integer-Wert. Wenn die Funktion aufgrund eines Fehlers nicht aufgerufen werden kann, ist der Rückgabewert leer (eine leere Zeichenkette).

[DllDatei\]Funktion

Der Name einer DLL- oder EXE-Datei, gefolgt von einem umgekehrten Schrägstrich und dem Namen der Funktion. Zum Beispiel: "MeineDLL\MeineFunktion" (standardmäßig gilt die Dateierweiterung ".dll", wenn sie weggelassen wird). Wenn kein absoluter Pfad angegeben ist, wird DllDatei in einem der Pfade aus der PATH-Umgebungsvariable oder im A_WorkingDir-Verzeichnis vermutet.

DllDatei kann weggelassen werden, wenn eine Funktion aus der User32.dll, Kernel32.dll, ComCtl32.dll oder Gdi32.dll aufgerufen wird. Zum Beispiel würde "User32\IsWindowVisible" das gleiche Ergebnis liefern wie "IsWindowVisible".

Wenn eine Funktion nicht über den angegebenen Namen gefunden werden kann, wird je nach AutoHotkey-Version automatisch ein A (ANSI) oder W (Unicode) angefügt. "MessageBox" wäre in einer ANSI-Version das gleiche wie "MessageBoxA" und in einer Unicode-Version das gleiche wie "MessageBoxW".

Um die Performance beim wiederholenden Aufrufen einer DLL-Datei drastisch zu verbessern, lädt man sie im Voraus.

In v1.0.46.08+ kann dieser Parameter auch ein reiner Integer sein, der als Adresse einer Funktion, die aufgerufen werden soll, 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, weil die meisten Funktionen auf die Standard-Aufrufkonvention statt C-Aufrufkonvention zurückgreifen (Funktionen wie wsprintf, die eine unterschiedliche Anzahl von Argumenten akzeptieren, sind so eine Ausnahme). Wenn Sie Cdecl weglassen, aber der Aufruf ErrorLevel An zurückgibt -- n ist die Gesamtgröße der Argumente, die Sie übergeben haben -- ist Cdecl eventuell erforderlich. Beachten Sie, dass die meisten objektorientierten C++-Funktionen die thiscall-Konvention nutzen, die in AutoHotkey nicht unterstützt wird.

Das Wort Cdecl sollte 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+]: In der 64-Bit-Version von AutoHotkey kann Cdecl zwar angegeben werden, aber bleibt wirkungslos, weil 64-Bit-Code keine separate C-Aufrufkonvention hat.

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

Argumenttypen und Rückgabewerte

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 würde z. B. den Inhalt von MeineVar in Großbuchstaben umwandeln: DllCall("CharUpper", "Str", MeineVar).

Wenn die Funktion jedoch darauf ausgelegt ist, eine Zeichenkette zu speichern, die größer als die aktuelle Kapazität einer Variable ist, müssen Sie vor dem Funktionsaufruf sicherstellen, dass die Variable groß genug ist. Um das zu erreichen, ruft man VarSetCapacity(MeineVar, 123) auf, dabei ist 123 die Länge, die MeineVar maximal enthalten soll.

Ein Str-Argument darf kein Ausdruck sein, der 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 zwar unterstützt, aber nur selten eingesetzt. Diese Variable 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). Unter Skript-Kompatibilität finden Sie gleichwertige Win32-Typen und weitere Details.
Int64 Ein 64-Bit-Integer im Zahlenbereich von -9223372036854775808 (-0x8000000000000000) bis 9223372036854775807 (0x7FFFFFFFFFFFFFFF).
Int

Ein 32-Bit-Integer (meistgenutzter Integer-Typ) im Zahlenbereich von -2147483648 (-0x80000000) bis 2147483647 (0x7FFFFFFF). Ein Int wird manchmal auch als "Long" bezeichnet.

Ein Int sollte auch genutzt werden, wenn die Funktion ein BOOL-Argument erwartet (ein BOOL-Wert sollte entweder 1 oder 0 sein).

Ein vorzeichenloser (unsigned) Integer (UInt) wird auch ziemlich oft genutzt, z. B. für DWORD.

Short Ein 16-Bit-Integer im Zahlenbereich von -32768 (-0x8000) bis 32767 (0x7FFF). Ein vorzeichenloser 16-Bit-Integer (UShort) kann bei Funktionen verwendet werden, die ein DWORD erwarten.
Char Ein 8-Bit-Integer im Zahlenbereich von -128 (-0x80) bis 127 (0x7F). Ein vorzeichenloser 8-Bit-Integer (UChar) kann bei Funktionen verwendet werden, die ein BYTE erwarten.
Float Eine 32-Bit-Gleitkommazahl mit maximal 6 Stellen nach dem Komma.
Double Eine 64-Bit-Gleitkommazahl mit maximal 15 Stellen nach dem Komma.
Ptr

[AHK_L 42+]: Ein pointer-großer Integer, der je nach Dateiformat der skript-ausführenden EXE-Datei (32- oder 64-Bit) einem Int oder Int64 entspricht. Ptr sollte für Pointer verwendet werden, die auf Arrays oder Strukturen (wie RECT* oder LPPOINT) verweisen, und für fast alle Handles (wie HWND, HBRUSH oder HBITMAP). Handelt es sich bei dem Parameter um einen Pointer, der auf einen einzelnen numerischen Wert wie LPDWORD oder int* verweist, sollte grundsätzlich das Suffix * oder P anstelle von "Ptr" verwendet werden.

Ptr kann auch mit dem Suffix * oder P kombiniert werden; diese Kombination sollte nur bei Funktionen verwendet werden, die einen Pointer über LPVOID* oder Ähnliches zurückgeben.

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

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

Ptr := A_PtrSize ? "Ptr" : "UInt" ; Wenn A_PtrSize nicht definiert ist, gilt stattdessen UInt.
DllCall("DeleteFile", Ptr, &Dateiname) ; Lass die Anführungszeichen bei Ptr weg.

Hinweis: Um einen NULL-Handle oder -Pointer zu übergeben, übergibt man den Integer 0.

* oder P
(Suffix)

Fügen Sie vor einem Sternchen (optional mit einem Leerzeichen davor) einen der oben genannten Typen an, wenn nicht der Wert selbst, sondern die Adresse des Arguments übergeben werden soll (die aufgerufene Funktion muss so konstruiert sein, dass sie so etwas akzeptieren kann). Die Funktion kann direkt auf den Wert von so einem Argument zugreifen; wenn man eine reine Variable als Argument übergibt, wird der Inhalt dieser Variable aktualisiert. Der folgende Aufruf würde z. B. den Inhalt von MeineVar via Adresse an MeineFunktion ü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 nutzt man ein Sternchen, wenn der Argument- oder Rückgabetyp einer Funktion 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 gibt man "UInt*" oder "UintP" an, um LPDWORD zu erhalten. 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 Sie eine Variable oder ihre Adresse übergeben wollen.

Hinweis: "Char*" ist nicht das gleiche wie "Str". Das ist deshalb so, weil "Char*" die Adresse einer 8-Bit-Zahl übergibt, während "Str" die Adresse einer Reihe von Zeichen übergibt, die je nach AutoHotkey-Version 8-Bit (ANSI) oder 16-Bit (Unicode) groß sind. So ähnlich verhält es sich mit "UInt*", das die Adresse einer 32-Bit-Zahl übergibt: Dieser Typ ist nicht für eine Funktion geeinigt, die ein Array mit Werten oder eine Struktur größer als 32 Bit erwartet.

Da die Variablen in AutoHotkey keinen festen Typ haben, verweist die Adresse, die an die Funktion übergeben wurde, nicht auf die Variable selbst, sondern auf einen temporären Speicher. Es ist nicht notwendig, VarSetCapacity auf die Variable anzuwenden, weil DllCall sie nach dem Durchführen der Funktion korrekt aktualisieren wird.

U (Präfix)

Fügen Sie nach dem Buchstaben U einen der oben genannten Integer-Typen an, wenn der Typ als vorzeichenloser Integer (UInt64, Uint, UShort und UChar) interpretiert werden soll. Streng genommen ist das nur für Rückgabewerte und Sternchenvariablen notwendig, da es keine Rolle spielt, ob ein Argument, der als Wert übergeben wurde, vorzeichenbehaftet oder vorzeichenlos ist (außer für Int64).

Wenn Sie für ein vorzeichenloses Argument einen negativen Integer angeben, wechselt der Integer in den vorzeichenlosen Bereich. Wenn Sie beispielsweise vorhaben, -1 als UInt zu senden, würde es zu 0xFFFFFFFF werden.

Vorzeichenlose 64-Bit-Integer, die eine Funktion erzeugt, werden nicht unterstützt. Um daher mit Zahlen zu hantieren, die größer gleich 0x8000000000000000 sind, lässt man das U-Präfix weg und interpretiert jeden negativen Wert, den die Funktion zurückgibt, als großen Integer. Zum Beispiel würde eine Funktion, die -1 als Int64 zurückgibt, eigentlich 0xFFFFFFFFFFFFFFFF zurückgeben, wenn sie ein UInt64 überhaupt zurückgeben kann.

Hinweis: Wenn man ein Argument- oder Rückgabetyp ohne Leerzeichen oder Sternchen angibt, können die Anführungszeichen weggelassen werden. Zum Beispiel kann Str anstelle von "Str" und CDecl anstelle von "CDecl" verwendet werden. Wenn der Buchstabe P anstelle des Sternchens verwendet wird, können die Anführungszeichen auch weggelassen werden. Zum Beispiel: UIntP.

ErrorLevel

[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 Gleitkommazahl. 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 eine Zahl ergibt, an ein Argument übergeben wird, das als Zeichenkette (Str) typisiert ist.

-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 wäre z. B. "Zugriffsverletzung"). In solchen Fällen gibt die Funktion einen leeren Wert (leere Zeichenkette) zurück, allerdings wird jede Sternchenvariable immer noch aktualisiert. Eine fatale Ausnahme wäre beispielsweise die Dereferenzierung eines ungültigen Pointers wie NULL. Aufgrund der Tatsache, dass eine Cdecl-Funktion nie den im nächsten Abschnitt erwähnten "An"-Fehler erzeugen kann, löst sie stattdessen eine Ausnahme aus, wenn ihr zu wenig Argumente übergeben wurde.

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, um wie viel Bytes die Argumentenliste falsch war. Ist n positiv, wurden zu viele Argumente (oder zu lange Argumente) übergeben, oder der Aufruf erfordert CDecl. Ist n negativ, wurden zu wenig Argumente übergeben. Um eine zuverlässige Operation der Funktion zu gewährleisten, muss dieses Problem behoben werden. So ein Fehler könnte auch darauf hindeuten, dass eine Ausnahme aufgetreten ist - in diesem Fall gibt die Funktion einen leeren Wert zurück. Beachten Sie, dass 64-Bit-Builds den ErrorLevel aufgrund der x64-Aufrufkonvention nie auf An setzen.

Ausnahmen und A_LastError

Trotz der internen Ausnahmebehandlung ist es immer noch möglich, dass DllCall ein Skript zum Absturz bringen kann. Dieses Problem kann auftreten, 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 man einen ungeeigneten Argument- oder Rückgabetyp angegeben hat, z. B. wenn man einen gewöhnlichen Integer, den eine Funktion zurückgibt, als Sternchenvariable oder Str typisiert.

Die interne Variable A_LastError enthält den Rückgabewert der Systemfunktion GetLastError(), die sofort nach einem Funktionsaufruf aufgerufen wird (hat keine messbaren Auswirkungen auf die Performance). A_LastError ist eine Nummer zwischen 0 und 4294967295 (immer in dezimaler Form, nicht hexadezimal). A_LastError ist wie ErrorLevel eine interne Variable, die pro Thread gesetzt wird; das heißt, dass die Inhalte solcher Variablen nicht geändert werden, selbst wenn der aktuelle Thread zwischendurch von einem anderen Thread unterbrochen wird. A_LastError wird aber auch von Run/RunWait gesetzt.

Performance

Um die Performance beim wiederholenden Aufrufen einer DLL-Datei drastisch zu verbessern, kann man sie im Voraus laden (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\BackupDateiErstellen", "Str", A_LoopFileFullPath)
DllCall("FreeLibrary", "Ptr", hModule)  ; Um Speicherplatz zu sparen, kann die DLL nach der Benutzung entladen werden.

In v1.0.46.08+ kann eine noch schnellere Performance erreicht werden, wenn man im Voraus die Adresse der Funktion abfragt. Zum Beispiel:

; Das folgende Beispiel zeigt, wie man LoadLibrary statt GetModuleHandle verwenden kann, 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 Funktion-enthaltene DLL normal vor dem Start des Skripts geladen ist, wird die Zeichenkette automatisch in eine Funktionsadresse aufgelöst. Diese interne Optimierung ist effektiver als das oben gezeigte Beispiel.

Um die Performance einer DllCall-Anweisung zu verbessern, wo Parametertypen ohne Anführungszeichen angegeben sind (z. B. Int statt "Int"), fügt man #NoEnv irgendwo im Skript ein.

Um die Performance bei der Übergabe einer Zeichenkette-enthaltenen Variable an eine Funktion, die die Länge der Zeichenkette nicht verändert, zu verbessern, übergibt man die Variable via Adresse (z. B. &MeineVar) und nicht als "str" (besonders wenn die Zeichenkette sehr lang ist). 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.

Um Funktionen, die die Adresse einer Struktur (oder eines Speicherblock-Arrays) akzeptieren, aufzurufen, speichert man die binären Rohdaten der Struktur in eine normale Variable. Die folgenden Schritte werden in der Regel angewendet:

1) Rufen Sie VarSetCapacity(MeineStruktur, 123, 0) auf, um sicherzustellen, dass der Speicherumfang der Zielvariable groß genug für die Struktur ist. Ersetzen Sie 123 mit einer Zahl, die mindestens so groß ist wie die Größe der Struktur. Die Null im letzten Parameter ist optional; sie initialisiert jedes Element mit einer binären Null, um einen häufigen Aufruf von NumPut() im nächsten Schritt zu verhindern.

2) Wenn die Zielfunktion die Werte anfänglich in der Struktur verwendet, muss NumPut(123, MeineStruktur, 4, "UInt") aufgerufen werden, um jedes Element zu initialisieren, das ungleich 0 sein soll. Ersetzen Sie 123 mit dem Integer, der in das Zielelement eingefügt werden soll (oder nutzen Sie &Var, um die Adresse einer Variable zu speichern). 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 ihn weg, falls das Element ein Pointer oder Handle ist.

3) Rufen Sie die Zielfunktion auf und übergeben Sie die Adresse von MeineStruktur als UInt-Argument (oder in AHK_L 42+ als Ptr-Argument). Zum Beispiel: DllCall("MeineDLL\MeineFunktion", Ptr, &MeineStruktur). Die Funktion wird einige der Elemente prüfen und/oder ändern.

4) Verwenden Sie MeinInteger := NumGet(MeineStruktur, 4, "UInt"), um beliebige Integer aus der Struktur abzurufen. Ersetzen Sie 4 mit dem Offset des Zielelements in der Struktur. 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. Ersetzen Sie "UInt" mit dem entsprechenden Typ oder lassen Sie ihn weg, falls das Element ein Pointer oder Handle ist.

In den Strukturbeispielen weiter unten wurden diese Schritte angewandt.

Bekannte Einschränkungen

Wenn die Adresse einer Variable (z. B. &MeineVar) an eine Funktion übergeben wird und diese Funktion die Länge des Variableninhalts ändert, kann der nachfolgende Gebrauch dieser Variable eventuell zu fehlerhaftem Verhalten führen. Um dieses Problem zu beheben, gibt es folgende Lösungen: 1) Übergeben Sie MeineVar nicht als Ptr/Adresse, sondern als "Str"-Argument; 2) Rufen Sie in v1.0.44.03+ VarSetCapacity(MeineVar, -1) auf, um die intern gespeicherte Länge der Variable nach dem Aufruf von DllCall zu aktualisieren.

Jede binäre Null, die via Funktion in eine Variable gespeichert wurde, versteckt alle Daten auf der rechten Seite der Null; das heißt, dass die meisten Befehle und Funktionen solche Daten weder abrufen noch ändern können. Solche Daten können jedoch via Adressoperator, NumPut/NumGet und DllCall selbst manipuliert werden.

Eine Funktion, die die Adresse von einer der Zeichenketten zurückgibt, die an sie übergeben wurde, gibt dieselbe Zeichenkette eventuell auf einer anderen Speicheradresse als erwartet zurück. Zum Beispiel würde der Aufruf von CharLower(CharUpper(MeineVar)) in einer anderen Programmiersprache normalerweise bewirken, dass der Inhalt von MeineVar in Kleinbuchstaben umgewandelt wird. Macht man aber das gleiche mit DllCall(), wäre MeineVar im Endeffekt groß geschrieben, weil CharLower eine andere/temporäre Zeichenkette bearbeitet hätte, dessen Inhalt identisch zu MeineVar war:

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

Um dieses Problem zu umgehen, ersetzt man die zwei oben unterstrichenen "Str"-Werte mit Ptr. Dadurch wird der Rückgabewert von CharUpper als reine Adresse interpretiert, der dann als Integer an CharLower übergeben wird.

Bestimmte Einschränkungen können auftreten, wenn es um Zeichenketten geht. Weitere Informationen finden Sie unter Skript-Kompatibilität.

Component Object Model (COM)

COM-Objekte, die für VBScript und ähnliche Sprachen zugänglich sind, kann AutoHotkey auch via ComObjCreate, ComObjGet, ComObjActive und interner Objektsyntax ansteuern.

Um COM-Objekte, die kein IDispatch unterstützen, in Verbindung mit DllCall nutzen zu können, ruft man die Adresse einer Funktion aus der virtuellen Funktionstabelle des Objekt-Interfaces ab. Weitere Informationen finden Sie im Beispiel weiter unten.

Der Großteil von .NET-Framework ist auch via COM und DllCall zugänglich. Siehe .NET Framework Interop (englisch).

Siehe auch

Skript-Kompatibilität, PostMessage, OnMessage(), RegisterCallback(), Run, VarSetCapacity, Funktionen, SysGet, MSDN Library

Beispiele

; Beispiel: Ruft die Windows-API-Funktion "MessageBox" auf und meldet, welchen Button der Benutzer gedrückt hat.

WelcherButton := DllCall("MessageBox", "Int", "0", "Str", "Ja oder Nein drücken", "Str", "Titel der Box", "Int", 4)
MsgBox Sie haben den Button #%WelcherButton% gedrückt.
; Beispiel: Ersetzt das Desktop-Hintergrundbild mit der angegebenen Bitmap-Datei (.bmp).

DllCall("SystemParametersInfo", UInt, 0x14, UInt, 0, Str, A_WinDir . "\winnt.bmp", UInt, 2)
; Beispiel: 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 ein HWND zurück.
    MsgBox Das Fenster ist nicht sichtbar.
; Beispiel: Ruft die API-Funktion wsprintf() auf, um die Zahl 432 mit führenden 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%
; Beispiel: Zeigt, wie man mit QueryPerformanceCounter() eine höhere Präzision als die 10 ms von A_TickCount erreichen kann.

DllCall("QueryPerformanceCounter", "Int64*", CounterDavor)
Sleep 1000
DllCall("QueryPerformanceCounter", "Int64*", CounterDanach)
MsgBox % "Die Differenz zwischen den Zeiten beträgt " . CounterDanach - CounterDavor
; Beispiel: Ein Hotkey, der vorübergehend die Geschwindigkeit des Mauszeigers verringert, um eine genauere Positionierung zu ermöglichen.
; Halten Sie die F1-Taste gedrückt, um den Mauszeiger zu verlangsamen. Lassen Sie sie 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, OrigMausTempo, 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, 0x71, UInt, 0, Ptr, OrigMausTempo, UInt, 0)  ; Stellt die ursprüngliche Geschwindigkeit wieder her.
; Beispiel: Wenn Sie die Eindeutige ID des Fensters und den Text oder das ClassNN eines seiner Steuerelemente übergeben,
; gibt die folgende Funktion das HWND (Eindeutige ID) dieses Steuerelements zurück.
; v1.0.43.06+: Diese Funktion wurde durch den folgenden Befehl ersetzt, der wesentlich präziser ist.

ControlGet, AusgabeVar, Hwnd,, ClassNN, Fenstertitel
; Beispiel: Überwacht das aktive Fenster und zeigt die Position der vertikalen Scrollleiste
; in seinem fokussierten Steuerelement an (in Echzeit). Erfordert v1.0.43.06+, weil es ControlGet Hwnd verwendet.

#Persistent
SetTimer, BeobachteScrollleiste, 100
return

BeobachteScrollleiste:
AktivesFenster := WinExist("A")
if not AktivesFenster  ; Kein aktives Fenster.
    return
ControlGetFocus, FokussiertesSteuerelement, ahk_id %AktivesFenster%
if not FokussiertesSteuerelement  ; Kein fokussiertes Steuerelement.
    return
; Zeigt die vertikale oder horizontale Position der Scrollleiste in einem ToolTip an:
ControlGet, UnterelementHWND, Hwnd,, %FokussiertesSteuerelement%, 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
; Beispiel: Dieses Skript schreibt etwas Text in eine Datei und liest ihn wieder 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.
; In AHK_L 42+ kann das gleiche 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
}
TestZeichenkette = 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.
DllCall("WriteFile", Ptr, hFile, Str, TestZeichenkette, UInt, StrLen(TestZeichenkette), UIntP, AktuellGeschriebeneBytes, 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, das sie genügend Kapazität zur Verfügung hat:
ZuLesendeBytes := VarSetCapacity(TestZeichenkette, StrLen(TestZeichenkette))
DllCall("ReadFile", Ptr, hFile, Str, TestZeichenkette, UInt, ZuLesendeBytes, UIntP, AktuellGeleseneBytes, Ptr, 0)
DllCall("CloseHandle", Ptr, hFile)  ; Schließt die Datei.
MsgBox Die folgende Zeichenkette wurde aus der Datei gelesen: %TestZeichenkette%
; Beispiel: Versteckt den Mauszeiger, wenn man WIN+C drückt. Um den Mauszeiger wieder sichtbar zu machen, drückt man nochmals WIN+C.
; 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 ein HWND 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 die FillRect-Funktion 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: Setzen Sie die Systemuhr auf den angegebenen Datums- und Zeitwert. Seien Sie vorsichtig,
; wenn Sie ein zukünftiges Datum setzen, denn dies kann dazu führen, dass geplante Tasks vorzeitig ausgeführt werden!

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

SetzeSystemzeit(YYYYMMDDHHMISS)
; Setzt die Systemzeit den angegebenen Datums- und Zeitwert.
; 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(Systemzeit, 16, 0)  ; Diese Struktur besteht aus 8 UShort-Werten (also 8*2=16).

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

    return DllCall("SetSystemTime", Ptr, &Systemzeit)
}
/* Weitere Struktur-Beispiele:

1) Im WinLIRC-Client-Skript wird gezeigt, wie man mit DllCall() eine Netzwerkverbindung zu einem TCP/IP-Server aufbauen und Daten von ihm empfangen kann.

2) Das Betriebssystem bietet vorgefertigte Dialogfenster an, die der Benutzer zum Auswählen einer Farbe, einer Schriftart oder eines Symbols verwenden kann.
Solche Dialogfenster nutzen Strukturen und werden auf www.autohotkey.com/forum/topic17230.html vorgestellt.

*/
/*
  Beispiel: 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)
}