CallbackCreate

Erstellt eine Maschinencode-Adresse, die, wenn aufgerufen, den Aufruf an eine Funktion im Skript weiterleitet.

Adresse := CallbackCreate(Funktion , Optionen, ParamAnzahl)

Parameter

Funktion

Typ: Funktionsobjekt

Ein Funktionsobjekt, das jedes Mal automatisch aufgerufen wird, wenn Adresse aufgerufen wird. Die Funktion empfängt auch die Parameter, die an Adresse übergeben wurden.

Ein Closure oder Bound-Funktion kann verwendet werden, um zwischen mehreren Rückrufen zu unterscheiden, die alle dieselbe Skriptfunktion aufrufen.

Der Rückruf reserviert für sich selbst eine Referenz zum Funktionsobjekt und gibt diese frei, wenn das Skript CallbackFree aufruft.

Optionen

Typ: Zeichenkette

Wenn leer oder weggelassen, wird jedes Mal, wenn Funktion aufgerufen wird, ein neuer Thread gestartet, und die Standardaufrufkonvention verwendet. Außerdem werden die Parameter einzeln an Funktion übergeben. Andernfalls geben Sie eine oder mehrere der folgenden Optionen an. Trennen Sie alle Optionen jeweils durch ein Leerzeichen (z.B. "C Fast").

Fast oder F: Verhindert, dass bei jedem Aufruf von Funktion ein neuer Thread gestartet wird. Trotz der daraus resultierenden besseren Performanz sollte diese Option nicht verwendet werden, wenn der Thread, von dem aus Adresse aufgerufen wird, variiert (z.B. wenn der Rückruf durch eine eingehende Meldung ausgelöst wurde). Der Grund dafür ist, dass Funktion globale Einstellungen wie A_LastError und das zuletzt gefundene Fenster für jeden Thread ändern kann, der zum Zeitpunkt des Aufrufs gerade läuft. Weitere Informationen finden Sie unter Bemerkungen.

CDecl oder C: Macht Adresse konform zur "C"-Aufrufkonvention. Dies wird normalerweise weggelassen, da die Standardaufrufkonvention für Rückrufe weitaus gebräuchlicher ist. Diese Option wird von den 64-Bit-Versionen von AutoHotkey, die die x64-Aufrufkonvention verwenden, ignoriert.

&: Bewirkt, dass die Parameter nicht einzeln, sondern als Parameterliste in Form einer Adresse (ein einzelner Integer) an Funktion übergeben werden. Parameterwerte können mit NumGet abgerufen werden. Wenn die reguläre 32-Bit-Aufrufkonvention verwendet wird, muss ParamAnzahl die Größe der Parameterliste in DWORDs angeben (die Anzahl der Bytes geteilt durch 4).

ParamAnzahl

Typ: Integer

Wenn weggelassen, wird standardmäßig Funktion.MinParam verwendet, was üblicherweise der Anzahl der Pflichtparameter in der Definition von Funktion entspricht. Andernfalls geben Sie die Anzahl der Parameter an, die der Aufrufer von Adresse übergeben wird. In beiden Fällen muss sichergestellt werden, dass der Aufrufer genau diese Anzahl von Parametern übergibt.

Rückgabewert

Typ: Integer

CallbackCreate gibt eine Maschinencode-Adresse zurück. Diese Adresse wird üblicherweise via DllCall an eine externe Funktion übergeben oder via NumPut in eine Struktur geschrieben, kann aber auch direkt von DllCall aufgerufen werden. Wenn die Adresse an CallbackFree übergeben wird, wird der Rückruf gelöscht.

Fehlerbehandlung

Diese Funktion schlägt fehl und löst eine Ausnahme aus, wenn eine der folgenden Bedingungen zutrifft:

Die Parameter von Funktion

Eine Funktion, die einer Rückrufadresse zugewiesen wurde, akzeptiert bis zu 31 Parameter. Optionale Parameter sind erlaubt; dies ist nützlich, wenn Funktion von mehr als einem Aufrufer aufgerufen wird.

Die korrekte Interpretation der Parameter erfordert ein gewisses Verständnis dafür, wie die x86-Aufrufkonventionen funktionieren. Da Autohotkey keine typisierten Parameter besitzt, wird davon ausgegangen, dass die Parameterliste des Rückrufs aus Integern besteht, was eine gewisse Neuinterpretation zur Folge haben kann.

AutoHotkey 32-Bit: Alle eingehenden Parameter sind vorzeichenlose 32-Bit-Integer. Kleinere Typen werden auf 32 Bit erweitert, während größere Typen in mehrere 32-Bit-Parameter aufgeteilt werden.

Wenn ein eingehender Parameter als vorzeichenfähiger Integer gedacht ist, können negative Zahlen mit einer der folgenden Methoden enthüllt werden:

; Methode #1
if (wParam > 0x7FFFFFFF)
    wParam := -(~wParam) - 1

; Methode #2: Verlässt sich darauf, dass AutoHotkey nativ vorzeichenfähige 64-Bit-Integer verwendet.
wParam := wParam << 32 >> 32

AutoHotkey 64-Bit: Alle eingehenden Parameter sind vorzeichenfähige 64-Bit-Integer. Nativ unterstützt AutoHotkey keine vorzeichenlose 64-Bit-Integer. Kleinere Typen werden auf 64 Bit erweitert, während größere Typen immer via Adresse übergeben werden.

AutoHotkey 32-Bit/64-Bit: Wenn ein eingehender Parameter als 8-Bit- oder 16-Bit-Wert (oder 32-Bit in x64) gedacht ist, können die höheren Bits des Wertes "Müll" enthalten, der aber mittels bitweisem UND herausgefiltert werden kann. Zum Beispiel:

Rückruf(UCharParam, UShortParam, UIntParam) {
    UCharParam &= 0xFF
    UShortParam &= 0xFFFF
    UIntParam &= 0xFFFFFFFF
    ;...
}

Wenn ein eingehender Parameter von seinem Aufrufer als Zeichenkette gedacht ist, dann ist das, was tatsächlich ankommt, die Adresse der Zeichenkette. Mit StrGet kann die Zeichenkette selbst abgerufen werden:

MeineZkette := StrGet(MeinParameter)

Wenn ein eingehender Parameter die Adresse einer Struktur ist, können die einzelnen Elemente durch Befolgen der Schritte in DllCall-Strukturen extrahiert werden.

Parameter via Adresse empfangen: Wenn die &-Option verwendet wird, empfängt Funktion die Adresse des ersten Rückrufparameters. Zum Beispiel:

Rückruf := CallbackCreate(DieFunk, "F&", 3)  ; Größe der Parameterliste muss für 32-Bit angegeben werden.
DllCall(Rückruf, "float", 10.5, "int64", 42)
DieFunk(params) {
    MsgBox NumGet(params, 0, "float") ", " NumGet(params, A_PtrSize, "int64")
}

Die meisten Rückrufe in 32-Bit-Programmen verwenden die stdcall-Aufrufkonvention, die eine feste Anzahl von Parametern voraussetzt. In solchen Fällen muss ParamAnzahl auf die Größe der Parameterliste gesetzt werden, wobei Int64 und Double als zwei 32-Bit-Parameter zählen. Bei Cdecl- oder 64-Bit-Aufrufkonventionen hat ParamAnzahl keine Wirkung.

Was Funktion zurückgeben muss

Wenn Funktion ein Return verwendet, dessen Parameter leer ist oder weggelassen wird, oder überhaupt kein Return verwendet, wird 0 an den Aufrufer des Rückrufs zurückgegeben. Andernfalls muss Funktion einen Integer zurückgeben, der dann an den Aufrufer zurückgegeben wird. Die 32-Bit-Version von AutoHotkey kürzt Rückgabewerte auf 32 Bit, während die 64-Bit-Version von AutoHotkey 64-Bit-Rückgabewerte unterstützt. Die Rückgabe von Strukturen größer als diese (nach Wert) wird nicht unterstützt.

Schnell vs. Langsam

Der reguläre/langsame Modus bewirkt, dass Funktion vorerst die Standardwerte von Einstellungen wie SendMode und DetectHiddenWindows verwendet. Diese Standardwerte können während der Startphase des Skripts geändert werden.

Der schnelle Modus hingegen erbt die globalen Einstellungen von jedem Thread, der zum Zeitpunkt des Aufrufs von Funktion gerade läuft. Außerdem werden alle Änderungen, die Funktion an den globalen Einstellungen (einschließlich dem zuletzt gefundenen Fenster) vornimmt, für den aktuellen Thread wirksam. Folglich sollte der schnelle Modus nur verwendet werden, wenn genau bekannt ist, in welchem Thread Funktion aufgerufen wird.

Um eine Unterbrechung durch sich selbst (oder einen anderen Thread) zu vermeiden, kann ein Rückruf Critical in seiner ersten Zeile verwenden. Dies ist jedoch nicht sehr effektiv, wenn Funktion indirekt über eine eingehende Meldung kleiner als 0x0312 aufgerufen wird (eine Erhöhung des Critical-Intervalls könnte helfen). Außerdem wird Funktion durch Critical nicht daran gehindert, etwas zu tun, was zu einem indirekten Selbstaufruf führen könnte, wie z.B. der Aufruf von SendMessage oder DllCall.

CallbackFree

Löscht einen Rückruf und gibt seine Referenz zum Funktionsobjekt frei.

CallbackFree(Adresse)

Jedes Mal, wenn CallbackCreate verwendet wird, wird eine kleine Menge an Speicher reserviert (32 oder 48 Bytes plus System-Overhead). Da das Betriebssystem diesen Speicher automatisch freigibt, wenn das Skript beendet wird, kann jedes Skript, das Speicher für eine kleine feste Anzahl von Rückrufen reserviert hat, ohne explizite Speicherfreigabe auskommen.

Wenn jedoch das vom Rückruf gehaltene Funktionsobjekt dynamischer Natur ist (wie z.B. Closure oder Bound-Funktion), kann die Freigabe des Rückrufs besonders dann wichtig sein, wenn er nicht mehr benötigt wird; andernfalls wird das Funktionsobjekt nicht freigegeben.

DllCall, OnMessage, OnExit, OnClipboardChange, Sort-Rückruffunktion, Critical, PostMessage, SendMessage, Funktionen, Windows-Meldungen, Threads

Beispiele

Zeigt eine Zusammenfassung aller Top-Level-Fenster an.

EnumAdresse := CallbackCreate(EnumWindowsProc, "Fast")  ; Schneller Modus ist okay, da es nur von diesem Thread aufgerufen wird.

DetectHiddenWindows True  ; Durch den schnellen Modus wird diese Einstellung auch für den Rückruf wirksam.

; Kontrolle an EnumWindows() übergeben, das den Rückruf wiederholt aufruft:
DllCall("EnumWindows", "Ptr", EnumAdresse, "Ptr", 0)
MsgBox Ausgabe  ; Die vom Rückruf gesammelten Informationen anzeigen.
    
EnumWindowsProc(hwnd, lParam)
{
    global Ausgabe
    Titel := WinGetTitle(hwnd)
    Klasse := WinGetClass(hwnd)
    if Titel
        Ausgabe .= "HWND: " hwnd "`tTitel: " Titel "`tKlasse: " Klasse "`n"
    return true  ; EnumWindows() fortfahren lassen, bis alle Fenster enumeriert wurden.
}

Zeigt, wie ein GUI-Fenster zu einer Unterklasse gemacht werden kann, indem dessen WindowProc an ein neues WindowProc weitergeleitet wird. In diesem Fall wird die Hintergrundfarbe des Text-Steuerelements auf eine benutzerdefinierte Farbe gesetzt.

TextHintergrundFarbe := 0xFFBBBB  ; Eine benutzerdefinierte Farbe im BGR-Format.
TextHintergrundPinsel := DllCall("CreateSolidBrush", "UInt", TextHintergrundFarbe)

MeineGui := Gui()
Text := MeineGui.Add("Text",, "Hier ein Text mit`nbenutzerdefinierter Hintergrundfarbe.")

; 64-Bit-Skripte müssen SetWindowLongPtr statt SetWindowLong aufrufen:
SetWindowLong := A_PtrSize=8 ? "SetWindowLongPtr" : "SetWindowLong"

WindowProcNeu := CallbackCreate(WindowProc)  ; Schnellen Modus beim Setzen der Unterklasse vermeiden.
WindowProcAlt := DllCall(SetWindowLong, "Ptr", MeineGui.Hwnd, "Int", -4  ; -4 ist GWL_WNDPROC
    , "Ptr", WindowProcNeu, "Ptr") ; Rückgabewert muss auf "Ptr" oder "UPtr" statt auf "Int" gesetzt werden.

MeineGui.Show

WindowProc(hwnd, uMsg, wParam, lParam)
{
    Critical
    if (uMsg = 0x0138 && lParam = Text.Hwnd)  ; 0x0138 ist WM_CTLCOLORSTATIC.
    {
        DllCall("SetBkColor", "Ptr", wParam, "UInt", TextHintergrundFarbe)
        return TextHintergrundPinsel  ; HBRUSH zurückgeben, um dem System mitzuteilen, dass wir HDC geändert haben.
    }
    ; Andernfalls (da oben nichts zurückgegeben wurde) alle unbehandelten Ereignisse an das originale WindowProc übergeben.
    return DllCall("CallWindowProc", "Ptr", WindowProcAlt, "Ptr", hwnd, "UInt", uMsg, "Ptr", wParam, "Ptr", lParam)
}