DllCall()

Ruft eine Funktion innerhalb 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 durch einen Fehler 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 Funktionsnamen. Zum Beispiel: "MeineDLL\MeineFunktion" (die Dateierweiterung ".dll" kann standardmäßig weggelassen werden). Solange kein absoluter Pfad angegeben ist, befindet sich die DllDatei im System- oder A_WorkingDir-Pfad.

DllDatei kann weggelassen werden, wenn eine Funktion in 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 automatisch ein A (ANSI) oder W (Unicode) angefügt, abhängig davon, welche Version von AutoHotkey das Skript ausführt. "MessageBox" wäre in einer ANSI-Version das gleiche wie "MessageBoxA" und in einer Unicode-Version das gleiche wie "MessageBoxW".

Bei wiederholenden Aufrufen einer DLL-Datei kann die Performance erheblich verbessert werden, indem man sie im Voraus lädt.

Seit v1.0.46.08 kann dieser Parameter auch ein reiner Integer sein, um die Adresse einer Funktion anzugeben, die aufgerufen werden soll. Quellen für solche Adressen sind COM und RegisterCallBack().

Typ1, Arg1

Jedes dieser Paare repräsentiert einen einzelnen Parameter, der an die Funktion übergeben werden soll. Die Anzahl an möglichen Paaren ist unbegrenzt. Bei Typ kann ein Typ aus der unteren Typentabelle angegeben werden. Bei Arg kann der Wert angegeben werden, der an die Funktion übergeben werden soll.

Cdecl Rückgabetyp

Das Wort Cdecl wird normalerweise weggelassen, weil die meisten Funktionen die Standard-Aufrufkonvention verwenden, statt die C-Aufrufkonvention (Funktionen wie wsprintf, die eine unterschiedliche Anzahl an Argumenten akzeptieren, bilden solch eine Ausnahme). Ergibt der Aufruf ErrorLevel An (n ist die Gesamtgröße an übergebenen Argumenten), während Sie Cdecl weglassen, wird Cdecl möglicherweise benötigt. Beachten Sie, dass die meisten objektorientierten C++-Funktionen die thiscall-Konvention verwenden, die in AutoHotkey nicht unterstützt wird.

Das Wort Cdecl sollte vor dem Rückgabetyp (falls vorhanden) stehen. Dabei muss jedes Wort mit einem Leer- oder Tabulatorzeichen getrennt werden. Zum Beispiel: "Cdecl Str".

[AHK_L 53+]: In den 64-Bit-Builds von AutoHotkey hat Cdecl keine Wirkung, weil es keine seperate C-Aufrufkonvention im 64-Bit-Code gibt.

Rückgabetyp: Wenn die Funktion einen vorzeichenbehafteten 32-Bit-Integer (Int), BOOL oder nichts zurückgibt, kann Rückgabetyp weggelassen werden. Ansonsten kann ein Argumenttyp aus der Typentabelle verwendet werden. 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 deren Inhalt aktualisiert. Zum Beispiel würde der folgende Aufruf den Inhalt von MeineVar in Großbuchstaben umwandeln: DllCall("CharUpper", "Str", MeineVar).

Wenn die Funktion allerdings in der Lage ist, eine Zeichenkette größer als die aktuelle Variablenkapazität zu speichern, muss sichergestellt werden, dass die Variable vor dem Funktionsaufruf groß genug ist. Verwenden Sie dazu VarSetCapacity(MeineVar, 123) - 123 wäre die Länge, die MeineVar haben soll.

Ein Str-Argument darf kein Ausdruck sein, der eine Zahl errechnet (z. B. i+1). In diesem Fall wird die Funktion nicht aufgerufen und ErrorLevel auf -2 gesetzt.

Die Sternchenvariable "Str*" wird unterstützt, aber nur selten verwendet. Sie kann bei Funktionen nützlich sein, die so etwas wie "TCHAR **" oder "LPTSTR *" erwarten.

Hinweis: Bei der Übergabe einer Zeichenkette an eine Funktion muss klar sein, welchen Zeichenketten-Typ 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 mit einem Bereich von -9223372036854775808 (-0x8000000000000000) bis 9223372036854775807 (0x7FFFFFFFFFFFFFFF).
Int

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

Int sollte auch verwendet 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 Bereich von -32768 (-0x8000) bis 32767 (0x7FFF). Ein vorzeichenloser 16-Bit-Integer (UShort) kann bei Funktionen verwendet werden, die DWORD erwarten.
Char Ein 8-Bit-Integer mit einem Bereich von -128 (-0x80) bis 127 (0x7F). Ein vorzeichenloser 8-Bit-Integer (UChar) kann bei Funktionen verwendet werden, die 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 Int oder Int64 entspricht, abhängig davon, ob die skript-ausführende EXE-Datei 32- oder 64-Bit ist. 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). Wenn der Parameter ein Pointer ist, der auf einen einzelnen numerischen Wert wie LPDWORD oder int* verweist, ist der *- oder P-Suffix besser geeignet als "Ptr".

Ptr kann auch den *- oder P-Suffix haben; es sollte nur bei Funktionen verwendet werden, die einen Pointer per LPVOID* oder Ähnliches zurückgeben.

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

Wenn die Kompatibilität mit älteren Versionen von AutoHotkey erforderlich ist, kann ein Variablentyp wie folgt verwendet werden:

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). Der Wert von so einem Argument könnte durch die Funktion geändert werden - wann immer man eine reine Variable als Argument übergibt, wird der Inhalt dieser Variable aktualisiert. Zum Beispiel würde der folgende Aufruf den Inhalt von MeineVar per Adresse an MeineFunktion übergeben, und auch MeineVar aktualisieren, um Änderung an ihr durch MeineFunktion widerzuspiegeln: DllCall("MeineDLL\MeineFunktion", "Int*", MeineVar).

In der Regel wird ein Sternchen verwendet, wann immer eine Funktion ein Argumenttyp 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, sollte für LPDWORD stattdessen "UInt*" oder "UintP" verwendet werden. Das Sternchen sollte nicht bei Zeichenkettentypen wie LPTSTR, auf Strukturen verweisende Pointer wie LPRECT, oder Arrays verwendet werden; für sie ist "Str" oder "Ptr" besser geeignet, abhängig davon, ob Sie eine Variable oder deren Adresse übergeben wollen.

Hinweis: "Char*" ist nicht das gleiche wie "Str", 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. Ebenso übergibt "UInt*" die Adresse einer 32-Bit-Zahl. Es sollte nicht verwendet werden, wenn die Funktion 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, auf einen temporären Speicher, anstatt auf die Variable selbst. 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 ein negativer Integer bei einem vorzeichenlosen Argument angegeben wurde, wechselt der Integer in den vorzeichenlosen Bereich. Wenn -1 beispielsweise als UInt gesendet wurde, wäre es 0xFFFFFFFF.

Von Funktionen erzeugte vorzeichenlose 64-Bit-Integer werden nicht unterstützt. Zahlen größer gleich 0x8000000000000000 können daher nur verwendet werden, wenn man das U-Präfix weglässt und jeden negativen Wert, der von der Funktion empfangen wurde, als großen Integer interpretiert. 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 könnte Str anstelle von "Str" und CDecl anstelle von "CDecl" verwendet werden. Darüber hinaus könnte der Buchstabe P anstelle des Sternchens verwendet werden, so dass auch dort die Anführungszeichen weggelassen werden können. Zum Beispiel: UIntP.

ErrorLevel

[v1.1.04+] Diese Funktion ist in der Lage, bei Misserfolg eine Ausnahme auszulösen. Für mehr Informationen, siehe 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 errechnet, an ein Zeichenkettenargument (Str) übergeben wird.

-3: Die angegebene DllDatei war weder zugreifbar noch konnte sie geladen werden. Wenn ein expliziter Pfad bei DllDatei fehlt, muss sich die Datei auf einen der Pfade aus der PATH-Umgebungsvariable oder A_WorkingDir befinden. Dieser Fehler kann auch auftreten, wenn dem Benutzer die nötigen Zugriffsrechte für die Datei fehlen, 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 (z. B. wäre 0xC0000005 "Zugriffsverletzung"). In solchen Fällen wird die Funktion eine leere Zeichenkette zurückgeben und jede Sternchenvariable weiter aktualisiert. Eine fatale Ausnahme wäre beispielsweise die Dereferenzierung eines ungültigen Pointers, wie z. B. NULL. Da eine Cdecl-Funktion nie den im nächsten Abschnitt erwähnten "An"-Fehler erzeugen kann, könnte sie eine Ausnahme generieren, wenn zu wenig Argumente an diese Funktion ü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 dabei die Anzahl an Bytes, mit denen 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. Dieses Problem sollte behoben werden, um eine zuverlässige Operation der Funktion zu gewährleisten. 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 aufgrund der x64-Aufrufkonvention ein 64-Bit-Build den ErrorLevel nie auf An setzt.

Ausnahmen und A_LastError

Trotz der internen Ausnahmebehandlung ist es möglich, dass ein Skript mit DllCall abstürzt. Dieses Problem kann auftreten, wenn eine Funktion nicht direkt eine Ausnahme erzeugt, sondern etwas Unangebrachtes zurückgibt, wie z. B. ein schlechter Pointer oder eine nicht-terminierte Zeichenkette. Die Funktion ist nicht unbedingt daran Schuld, wenn das Skript ihr einen ungeeigneten Wert übergibt, wie z. B. einen schlechten 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. mit der Behauptung, dass ein gewöhnlicher Integer, der von einer Funktion zurückgegeben wurde, eine Sternchenvariable oder Str ist.

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). Wie ErrorLevel auch, ist A_LastError eine Pro-Thread-Einstellung; das heißt, dass Unterbrechungen durch andere Threads den Wert nicht ändern können. Allerdings wird A_LastError auch von Run/RunWait gesetzt.

Performance

Bei wiederholenden Aufrufen einer DLL-Datei kann die Performance erheblich verbessert werden, indem man sie explizit lädt (unnötig bei einer Standard-DLL wie User32, weil sie dauerhaft im Arbeitsspeicher vorhanden ist). Diese Methode verhindert, dass für DllCall jedesmal LoadLibrary und FreeLibrary intern aufgerufen werden muss. Zum Beispiel:

hModule := DllCall("LoadLibrary", "Str", "MeineFunktionen.dll", "Ptr")  ; Verhindert, dass DllCall() die Library in der Schleife laden muss.
Loop, C:\Meine Dokumente\*.*, , 1
    Ergebnis := DllCall("MeineFunktionen\BackupFile", "Str", A_LoopFileFullPath)
DllCall("FreeLibrary", "Ptr", hModule)  ; Um Speicher freizugeben, kann die DLL nach ihrer Verwendung entladen werden.

Seit v1.0.46.08 kann eine noch schnellere Performance erreicht werden, wenn man im Voraus die Adresse der Funktion nachschlägt. Zum Beispiel:

; Das folgende Beispiel zeigt, wie man LoadLibrary anstelle von 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 DLL mit der Funktion normal vor dem Skriptstart geladen wurde, wird die Zeichenkette automatisch in eine Funktionsadresse aufgelöst. Diese interne Optimierung ist effektiver als das oben gezeigte Beispiel.

Auch das Hinzufügen von #NoEnv irgendwo im Skript verbessert die Performance von DllCall, wenn Parametertypen ohne Anführungszeichen verwendet werden (z. B. Int vs. "Int").

Beim Übergeben einer Zeichenkettenvariable an eine Funktion, die die Länge des Strings unverändert lässt, kann die Performance verbessert werden, wenn man die Variable per Adresse (z. B. &MeineVar) übergibt und nicht als "str" (besonders bei einer sehr langen Zeichenkette). 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 Speicher-Block-Arrays) akzeptieren, können aufgerufen werden, wenn man die binären Rohdaten der Struktur in eine normale Variable speichert. Die folgenden Schritte werden in der Regel durchgeführt:

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 Strukturgröße. 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 anfangs 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 verwende &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 geeigneten Typ oder lassen Sie es weg, falls das Element ein Pointer oder Handle ist.

3) Rufen Sie die Zielfunktion auf, indem Sie die Adresse von MeineStruktur als UInt-Argument (oder seit AHK_L 42 als Ptr-Argument) übergeben. Zum Beispiel: DllCall("MeineDLL\MeineFunktion", Ptr, &MeineStruktur). Die Funktion wird einige Elemente untersuchen 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 ist immer bei Offset 0. Das zweite Element ist bei Offset 0 plus die Größe des ersten Elements (in der Regel 4). Elemente nach dem zweiten sind bei dem Offset des vorherigen Feldes plus die Größe des vorherigen Feldes. Die meisten Elemente wie DWORD, INT und andere Typen von 32-Bit-Integer haben eine Größe von 4 Bytes. Ersetzen Sie "UInt" mit dem geeigneten Typ oder lassen Sie es weg, falls das Element ein Pointer oder Handle ist.

Siehe Strukturbeispiele für weitere Verwendungsmöglichkeiten.

Bekannte Einschränkungen

Wenn die Adresse einer Variable (z. B. &MeineVar) an eine Funktion übergeben wird und die Funktion die Länge des Variableninhalts ändert, verhält sich die Variable bei nachfolgender Verwendung nicht mehr korrekt. Um dieses Problem zu beheben, gibt es folgende Lösungen: 1) Übergeben Sie MeineVar nicht als Ptr/Adresse, sondern als "Str"-Argument; 2) Seit v1.0.44.03 kann VarSetCapacity(MeineVar, -1) aufgerufen werden, um die intern gespeicherte Länge der Variable zu aktualisieren, nachdem DllCall aufgerufen wurde.

Jede binäre Null, die per Funktion in eine Variable gespeichert wurde, versteckt alle Daten, die rechts neben der Null vorkommen; das heißt, dass solche Daten weder zugreifbar sind noch von den meisten Befehlen und Funktionen geändert werden können. Allerdings können solche Daten per Adressoperatoren, NumPut/NumGet und DllCall selbst manipuliert werden.

Eine Funktion, die die Adresse von einer der übergebenen Zeichenketten zurückgibt, könnte eine gleiche Zeichenkette zurückgeben, aber auf einer anderen Speicheradresse als erwartet. Zum Beispiel würde der Aufruf von CharLower(CharUpper(MeineVar)) in einer Programmiersprache dazu führen, dass der Inhalt von MeineVar in Kleinbuchstaben umgewandelt wird. Macht man aber das gleiche mit DllCall(), würde MeineVar nach folgendem Aufruf großgeschrieben sein, weil CharLower eine andere/temporäre Zeichenkette bearbeitet hat, 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 unterstrichenen "Str"-Werte oben 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. Für weitere Informationen, siehe Skript-Kompatibilität.

Component Object Model (COM)

COM-Objekte, die per VBScript und ähnliche Sprachen zugreifbar sind, kann man üblicherweise auch über AutoHotkey via ComObjCreate, ComObjGet, ComObjActive und interner Objekt-Syntax zugreifen.

COM-Objekte, die IDispatch nicht unterstützen, können mit DllCall verwendet werden, wenn man die Adresse einer Funktion von der virtuellen Funktionstabelle des Objekt-Interfaces ermittelt. Für weitere Details, siehe das Beispiel weiter unten.

Der größte Teil von .NET-Framework ist auch über COM und DllCall zugreifbar. 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 Editor-Fenster sichtbar ist.

DetectHiddenWindows On
if not DllCall("IsWindowVisible", "Ptr", WinExist("Unbenannt - Editor"))  ; WinExist() gibt HWND zurück.
    MsgBox Das Fenster ist nicht sichtbar.
; Beispiel: Ruft die API-Funktion wsprintf() auf, um die Zahl 432 bis zu 10 Zeichen mit führenden Nullen zu erweitern (0000000432).

VarSetCapacity(ErweiterteZahl, 20)  ; Stellt sicher, dass die Variable groß genug für die neue Zeichenkette ist.
DllCall("wsprintf", "Str", ErweiterteZahl, "Str", "%010d", "Int", 432, "Cdecl")  ; Benötigt die Cdecl-Aufrufkonvention.
MsgBox %ErweiterteZahl%
; Beispiel: Zeigt, wie man mit QueryPerformanceCounter() eine höhere Präzision erreichen kann, als die 10 ms von A_TickCount.

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. Lass 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)
; Nun wird die Geschwindigkeit des Mauszeigers im vorletzten Parameter verringert (von 1 bis 20, 10 ist Standard):
DllCall("SystemParametersInfo", UInt, SPI_SETMOUSESPEED, UInt, 0, Ptr, 3, UInt, 0)
KeyWait F1  ; Dies hindert die Auto-Wiederholung der Tastatur daran, DllCall wiederholend aufzurufen.
return

F1 up::DllCall("SystemParametersInfo", UInt, 0x71, UInt, 0, Ptr, OrigMausTempo, UInt, 0)  ; Stellt die ursprüngliche Geschwindigkeit wieder her.
; Beispiel: Beim Übergeben einer eindeutigen ID und des Textes oder der ClassNN von einem der Steuerelemente des Fensters
; gibt die folgende Funktion das HWND (eindeutige ID) des Steuerelements zurück.
; v1.0.43.06+: Diese Funktion wurde von folgendem Befehl ersetzt, der genauer ist.

ControlGet, AusgabeVar, Hwnd,, ClassNN, Fenstertitel
; Beispiel: Überwacht das aktive Fenster und zeigt die Position der vertikalen Scrollleiste
; im 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 schont die Performance beim Lesen oder Schreiben von mehrere Dateien gleichzeitig.
; Seit 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.

; Nachdem die Datei geschrieben wurde, soll deren Inhalt zurück in den Speicher gelesen werden.
GENERIC_READ = 0x80000000  ; Öffnet die Datei zum Lesen.
OPEN_EXISTING = 3  ; Datei muss existieren, bevor sie geöffnet werden kann.
FILE_SHARE_READ = 0x1 ; Diese und die nächste Variable bestimmen, ob andere Prozesse die 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 für weitere Testzwecke leer, aber stellt sicher, das genügend Kapazität zur Verfügung steht:
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")  ; WIN+C, um Mauszeiger ein- und auszuschalten.

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 Standardzeiger
    if (OnOff = "Init" or OnOff = "I" or $ = "")       ; initialisieren, wenn benötigt oder erster 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 GetWindowRect(), das die
; Strukturelemente auf die Positionen der linken, oberen,
; rechten und unteren Seite des Fensters setzt (bezogen auf dem Bildschirm).

Run Notepad
WinWait Unbenannt - Editor  ; Setzt auch das "zuletzt gefundene Fenster" für das untere WinExist().
VarSetCapacity(Rect, 16)  ; RECT ist eine Struktur, bestehend aus vier 32-Bit-Integern (also 4 * 4 = 16).
DllCall("GetWindowRect", Ptr, WinExist(), Ptr, &Rect)  ; WinExist() gibt 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 die Adresse einer RECT-Struktur an FillRect(), um den
; Bildschirm kurzzeitig rot zu färben.

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 0, um den Gerätekontext vom Desktop zu ermitteln.
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 mithilfe des oberen Pinsels.
DllCall("ReleaseDC", "Ptr", 0, "Ptr", hDC)  ; Gibt Speicher frei.
DllCall("DeleteObject", "Ptr", hBrush)  ; Gibt Speicher frei.
; Struktur-Beispiel: Ändert Datum und Zeit der Systemuhr. Aber sei gewarnt:
; Sobald die Uhr auf ein zukünftiges Datum gesetzt wird, kann es passieren, dass geplante Tasks vorzeitig ausgeführt werden!

SetzeSystemzeit("20051008142211")  ; Zeitstempel übergeben (lokal, nicht UTC).

SetzeSystemzeit(YYYYMMDDHHMISS)
; Setzt die Systemzeit auf das angegebene Datum und Zeit.
; Der Aufrufer muss sicherstellen, dass der eingehende Parameter ein gültiger Zeitstempel ist
; (lokale Zeit, nicht UTC). Bei Erfolg wird eine Zahl ungleich 0 zurückgegeben.
{
    ; Konvertiert für SetzeSystemzeit() den Parameter von lokale Zeit in UTC.
    UTC_Delta -= A_NowUTC, Seconds  ; Sekunden sind aufgrund des Rundungsproblems genauer.
    UTC_Delta := Round(-UTC_Delta/60)  ; Rundet auf die nächste Minute.
    YYYYMMDDHHMISS += UTC_Delta, Minutes  ; Wendet Offset zum Konvertieren auf UTC an.

    VarSetCapacity(Systemzeit, 16, 0)  ; Diese Struktur besteht aus 8 UShort-Werte (d. h. 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-Befehle:

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 besitzt Standard-Fensterdialoge zum Auswählen von Farben, Schriftarten oder Symbole.
Solche Fensterdialoge verwenden Strukturen und werden auf www.autohotkey.com/forum/topic17230.html gezeigt.

*/
/*
  Beispiel: Entfernt mithilfe von COM vorübergehend das aktive Fenster aus der Taskleiste.

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

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

activeHwnd := WinExist("A")

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

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

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