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

Typ: Zeichenkette oder Integer

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 W (Unicode) angefügt. Zum Beispiel ist "MessageBox" dasselbe wie "MessageBoxW".

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

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 CallbackCreate.

Wenn dieser Parameter ein Objekt ist, wird der Wert der Ptr-Eigenschaft des Objekts verwendet. Wenn diese Eigenschaft nicht existiert, wird ein PropertyError ausgelöst.

Typ1, Arg1

Typ: Zeichenkette

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

Typ: Zeichenkette

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). 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".

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

Typ: Zeichenkette oder Integer

DllCall gibt den Rückgabewert von Funktion zurück. Wenn Funktion keinen Rückgabewert hat, ist das Ergebnis ein undefinierter Wert des angegebenen Rückgabetyps (standardmäßig Integer).

Typen von Argumenten und Rückgabewerten

Typ Beschreibung
Str

Eine Zeichenkette wie z.B. "Blau" oder MeineVar, oder eine VarRef wie z.B. &MeineVar. Wenn die aufgerufene Funktion die Zeichenkette ändert und das Argument eine reine Variable oder eine VarRef 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 eine Zeichenkette zurückgibt, die länger ist als der Eingabewert des Parameters (oder wenn der Parameter nur für die Ausgabe bestimmt ist), wird die folgende Vorgehensweise empfohlen: 1) Erstellen Sie ein Buffer, 2) übergeben Sie es mit dem Ptr-Typ, und 3) rufen Sie die Zeichenkette nach Abschluss der Funktion mit StrGet ab, wie im wsprintf-Beispiel gezeigt.

Andernfalls sollten Sie vor dem Funktionsaufruf sicherstellen, dass die Variable groß genug ist. Rufen Sie hierfür VarSetStrCapacity(&MeineVar, 123) auf, wobei 123 die Anzahl der 16-Bit-Einheiten (umgangssprachlich auch Zeichen genannt) ist, die MeineVar maximal enthalten soll. Wenn die Variable bei Return nicht nullterminiert ist, wird eine Fehlermeldung angezeigt und das Programm beendet, da wahrscheinlich der Speicher durch einen Pufferüberlauf korrumpiert wurde. Dies deutet typischerweise darauf hin, dass die Kapazität der Variable unzureichend war.

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 ein TypeError ausgelöst.

Der selten verwendete Str*-Argumenttyp übergibt die Adresse einer temporären Variable, die die Adresse der Zeichenkette enthält. Wenn die Funktion eine neue Adresse in die temporäre Variable schreibt, wird die neue Zeichenkette in die Variable des Skripts kopiert, sofern eine VarRef übergeben wurde. Dies kann für Funktionen verwendet werden, die so etwas wie "TCHAR **" oder "LPTSTR *" erwarten. Wenn die Funktion jedoch Speicher reserviert und erwartet, dass der Aufrufer ihn wieder freigibt (z.B. durch Aufruf von CoTaskMemFree), muss stattdessen der Ptr*-Argumenttyp verwendet werden.

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

WStr Da AutoHotkey nativ UTF-16 verwendet, ist WStr (Wide Character String) äquivalent zu Str.
AStr

AStr bewirkt, dass der Eingabewert automatisch in ANSI umgewandelt wird. Da der für diese Umwandlung verwendete temporäre Speicher nur groß genug für die umgewandelte Eingabezeichenkette ist, werden alle Werte, die die Funktion in diese Zeichenkette schreibt, verworfen. Um eine ANSI-Zeichenkette als Ausgabeparameter zu empfangen, gehen Sie wie folgt vor:

buf := Buffer(Länge)  ; Temporären Pufferspeicher reservieren.
DllCall("Funktion", "ptr", buf)  ; Pufferspeicher an Funktion übergeben.
str := StrGet(buf, "cp0")  ; ANSI-Zeichenkette aus dem Pufferspeicher abrufen.

Der selten verwendete AStr*-Argumenttyp wird ebenfalls unterstützt und verhält sich ähnlich wie der Str*-Typ, außer dass jede neue Zeichenkette von ANSI in das native Format (UTF-16) umgewandelt wird.

Weitere Informationen und äquivalente Win32-Typen finden Sie unter Binärkompatibilitä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

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.

Wenn ein Objekt an einen Ptr-Parameter übergeben wird, wird der Wert der Ptr-Eigenschaft des Objekts verwendet. Wenn diese Eigenschaft nicht existiert, wird ein PropertyError ausgelöst. Das Objekt ist typischerweise ein Buffer.

Wenn ein Objekt an einen Ptr*-Parameter übergeben wird, wird der Wert der Ptr-Eigenschaft des Objekts vor dem Aufruf abgerufen und die Adresse einer temporären Variable, die diesen Wert enthält, an die Funktion übergeben. Nach Abschluss der Funktion wird der neue Wert wieder der Ptr-Eigenschaft des Objekts zugewiesen.

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.

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 VarRef als Argument übergeben wird, der Inhalt der Variable nach Abschluss der Funktion 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 eine Zeichenkette, eine Adresse oder ein Buffer übergeben wird.

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 16-Bit (Unicode) oder 8-Bit (für "AStr") 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 des Aufrufers.

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.

HRESULT

Ein 32-Bit-Integer. Dies wird grundsätzlich für COM-Funktionen verwendet und ist nur als Rückgabetyp ohne Präfix oder Suffix gültig. Fehlerwerte (wie durch das FAILED-Makro definiert) werden nie zurückgegeben; stattdessen wird ein OSError ausgelöst. Daher ist der Rückgabewert ein Erfolgscode im Bereich von 0 bis 2147483647.

HRESULT ist der reguläre Rückgabetyp für ComCall.

Fehlerbehandlung

DllCall löst einen Error aus, wenn eine der folgenden Bedingungen zutrifft:

Native 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 das Ergebnis der Systemfunktion GetLastError().

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 Files, "C:\Meine Dokumente\*.*", "R"
    Ergebnis := DllCall("MeineFunktionen\DateiSichern", "Str", A_LoopFilePath)
DllCall("FreeLibrary", "Ptr", hModule)  ; Um Speicherplatz zu sparen, kann die DLL nach Gebrauch wieder freigegeben werden.

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)

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, oder erfolgreich mit #DllLoad geladen wurde, wird die Zeichenkette automatisch in eine Funktionsadresse aufgelöst. Diese interne Optimierung ist effizienter als das obige Beispiel.

Ü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. StrPtr(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", StrPtr(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 Speicher auf irgendeine Weise reserviert und die Speicheradresse an die Funktion übergibt. Hierfür wird das Buffer-Objekt empfohlen. In der Regel geht man wie folgt vor:

1) Rufen Sie MeineStrukt := Buffer(123, 0) auf, um Pufferspeicher für die Strukturdaten zu reservieren. Ersetzen Sie 123 mit einer Zahl, die mindestens der Größe der Struktur entspricht (in Bytes). 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("UInt", 123, MeineStrukt, 4) 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 StrPtr(Var) an, um die Adresse einer Zeichenkette zu hinterlegen). Ersetzen Sie 4 mit dem Offset des Zielelements (siehe Schritt #4, was ein "Offset" ist). Ersetzen Sie "UInt" mit dem entsprechenden Typ, z.B. "Ptr", wenn das Element ein Pointer oder Handle ist.

3) Rufen Sie die Zielfunktion auf und übergeben Sie MeineStrukt als Ptr-Argument. Zum Beispiel DllCall("MeineDLL\MeineFunk", "Ptr", MeineStrukt). Die Funktion wird einige Elemente auswerten und/oder ändern. DllCall verwendet automatisch die Adresse des Pufferspeichers, die normalerweise mit MeineStrukt.Ptr abgerufen wird.

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 Zeichenkettenadresse einer Variable (z.B. StrPtr(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) Rufen Sie VarSetStrCapacity(&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, kann als Terminator fungieren, wodurch alle Daten rechts von der Null von den meisten internen Funktionen weder abgerufen noch geändert werden können. Allerdings können solche Daten manipuliert werden, indem die Adresse der Zeichenkette via StrPtr abgerufen und an andere Funktionen wie NumPut, NumGet, StrGet, StrPut und DllCall selbst übergeben wird.

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 Binärkompatibilitä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 ComObject, 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. Allerdings ist es in der Regel besser, ComCall zu verwenden, was diese Prozedur vereinfacht.

.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.

Binärkompatibilität, Buffer-Objekt, ComCall, PostMessage, OnMessage, CallbackCreate, Run, VarSetStrCapacity, Funktionen, SysGet, #DllLoad, Windows API Index

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 True
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).

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

; Alternativ kann die Format-Funktion mit dem Null-Flag verwendet 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 := 0)
DllCall("QueryPerformanceCounter", "Int64*", &CounterDavor := 0)
Sleep 1000
DllCall("QueryPerformanceCounter", "Int64*", &CounterDanach := 0)
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::
F1 up::
{
    static SPI_GETMOUSESPEED := 0x70
    static SPI_SETMOUSESPEED := 0x71
    static OrigMausGeschw := 0
    
    switch ThisHotkey
    {
    case "F1":
        ; Ruft die aktuelle Geschwindigkeit ab, um sie später wiederherzustellen:
        DllCall("SystemParametersInfo", "UInt", SPI_GETMOUSESPEED, "UInt", 0, "Ptr*", &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.
        
    case "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).

SetTimer ScrollbalkenÜberwachen, 100

ScrollbalkenÜberwachen()
{
    FokusHwnd := 0
    try FokusHwnd := ControlGetFocus("A")
    if !FokusHwnd  ; Kein Steuerelement fokussiert.
        return
    ; Vertikale oder horizontale Position des Scrollbalkens in einem Tooltip anzeigen:
    ToolTip DllCall("GetScrollPos", "Ptr", FokusHwnd, "Int", 1)  ;  Letzter Parameter kann 1 für SB_VERT und 0 für SB_HORZ sein.
}

Schreibt etwas Text in eine Datei und liest ihn zurück in den Speicher. Diese Methode ist performanter, wenn es darum geht, mehrere Dateien simultan zu lesen oder zu schreiben. Alternativ kann FileOpen verwendet werden, um denselben Effekt zu erzielen.

DateiName := FileSelect("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 !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.
ZketteGröße := StrLen(TestZkette) * 2
DllCall("WriteFile", "Ptr", hFile, "Str", TestZkette, "UInt", ZketteGröße, "UIntP", &RealGeschriebeneBytes := 0, "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 !hFile
{
    MsgBox "Kann '" DateiName "' nicht zum Lesen öffnen."
    return
}
; Reserviert einen Bereich im Speicher für die zu lesende Zeichenkette:
Puf := Buffer(ZketteGröße)
DllCall("ReadFile", "Ptr", hFile, "Ptr", Puf, "UInt", Puf.Size, "UIntP", &RealGeleseneBytes := 0, "Ptr", 0)
DllCall("CloseHandle", "Ptr", hFile)  ; Schließt die Datei.
MsgBox "Die folgende Zeichenkette wurde aus der Datei gelesen: " StrGet(Puf)

Versteckt den Mauszeiger, wenn Sie WIN+C drücken. Um den Mauszeiger wieder sichtbar zu machen, drücken Sie diesen Hotkey erneut.

OnExit (*) => SystemCursor("Show")  ; Stellt sicher, dass der Mauszeiger bei Beendigung des Skripts wieder sichtbar gemacht wird.

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

SystemCursor(cmd)  ; cmd = "Show|Hide|Toggle|Reload"
{
    static visible := true, c := Map()
    static sys_cursors := [32512, 32513, 32514, 32515, 32516, 32642
                         , 32643, 32644, 32645, 32646, 32648, 32649, 32650]
    if (cmd = "Reload" or !c.Count)  ; Neu laden bei Bedarf oder beim ersten Aufruf.
    {
        for i, id in sys_cursors
        {
            h_cursor  := DllCall("LoadCursor", "Ptr", 0, "Ptr", id)
            h_default := DllCall("CopyImage", "Ptr", h_cursor, "UInt", 2
                , "Int", 0, "Int", 0, "UInt", 0)
            h_blank   := DllCall("CreateCursor", "Ptr", 0, "Int", 0, "Int", 0
                , "Int", 32, "Int", 32
                , "Ptr", Buffer(32*4, 0xFF)
                , "Ptr", Buffer(32*4, 0))
            c[id] := {default: h_default, blank: h_blank}
        }
    }
    switch cmd
    {
    case "Show": visible := true
    case "Hide": visible := false
    case "Toggle": visible := !visible
    default: return
    }
    for id, handles in c
    {
        h_cursor := DllCall("CopyImage"
            , "Ptr", visible ? handles.default : handles.blank
            , "UInt", 2, "Int", 0, "Int", 0, "UInt", 0)
        DllCall("SetSystemCursor", "Ptr", h_cursor, "UInt", id)
    }
}

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.
Rect := Buffer(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.
L := NumGet(Rect, 0, "Int"), O := NumGet(Rect, 4, "Int")
R := NumGet(Rect, 8, "Int"), U := NumGet(Rect, 12, "Int")
MsgBox Format("Links {1} Oben {2} Rechts {3} Unten {4}", L, O, R, U)

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

Rect := Buffer(16)  ; Setzt die Kapazität zum Speichern von vier 4-Byte-Integern.
NumPut( "Int", 0                  ; links
      , "Int", 0                  ; oben
      , "Int", A_ScreenWidth//2   ; rechts
      , "Int", A_ScreenHeight//2  ; unten
      , Rect)
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 := DateDiff(A_Now, 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 := DateAdd(YYYYMMDDHHMISS, UTC_Delta, "Minutes")  ; Wendet den Offset für die Konvertierung zu UTC an.

    Systemuhr := Buffer(16)  ; Diese Struktur besteht aus 8 UShorts (also 8*2=16).

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

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

Weitere Strukturbeispiele:

Entfernt das aktive Fenster für 3 Sekunden aus der Taskleiste. Äquivalent zum ComCall-Beispiel.

/*
  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}"

; Das TaskbarList-Objekt erstellen.
tbl := ComObject(CLSID_TaskbarList, IID_ITaskbarList)

activeHwnd := WinExist("A")

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

; Nicht-gewrappte Interface-Pointer müssen manuell freigegeben werden.
ObjRelease(tbl.ptr)

vtable(ptr, n) {
    ; NumGet(ptr, "ptr") 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, "ptr"), n*A_PtrSize, "ptr")
}