ComCall

Ruft eine native COM-Interface-Methode per Index auf.

Ergebnis := ComCall(Index, ComObj , Typ1, Arg1, Typ2, Arg2, RückgabeTyp)

Parameter

Index

Typ: Integer

Die nullbasierte Indexnummer der Methode innerhalb der virtuellen Funktionstabelle.

Index entspricht der Position der Methode innerhalb der ursprünglichen Interface-Definition. Die Microsoft-Dokumentation listet Methoden grundsätzlich in alphabetischer Reihenfolge auf und eignet sich daher nicht zur Ermittlung der Indexnummer. Um die richtige Indexnummer zu ermitteln, muss die ursprüngliche Interface-Definition lokalisiert werden. Dies kann z.B. in einer Header-Datei oder einer Typbibliothek sein.

Es ist wichtig, Methoden zu berücksichtigen, die von übergeordneten Interfaces geerbt wurden. Da alle COM-Interfaces letztlich von IUnknown abgeleitet sind, sind die ersten drei Methoden immer QueryInterface (0), AddRef (1) und Release (2). Zum Beispiel ist IShellItem2 eine Erweiterung von IShellItem, die bei Index 3 beginnt und 5 Methoden enthält, daher ist die erste Methode von IShellItem2 bei Index 8.

Tipp: Die von Microsoft definierten COM-Interfaces finden Sie im Internet oder Windows SDK unter "IInterfaceNameVtbl" - zum Beispiel "IUnknownVtbl". Die Microsoft-eigenen Interface-Definitionen werden von dieser Plain-C-Definition der virtuellen Funktionstabelle des Interfaces begleitet, die alle Methoden explizit auflistet, in korrekter Reihenfolge.

Die Übergabe einer ungültigen Indexnummer kann zu undefiniertem Verhalten führen, inklusive (aber nicht beschränkt auf) Programmterminierung.

ComObj

Typ: Integer oder Objekt

Das gewünschte COM-Objekt; also ein COM-Interface-Pointer. Der Pointer-Wert kann direkt übergeben werden oder innerhalb eines Objekts mit der Ptr-Eigenschaft gekapselt sein, wie z.B. ein ComValue mit dem Variantentyp VT_UNKNOWN.

Der Interface-Pointer dient zur Lokalisierung der Adresse der virtuellen Funktion, die die Interface-Methode implementiert, und wird auch als Parameter übergeben. Dieser Parameter ist grundsätzlich nicht explizit in Sprachen enthalten, die Interfaces nativ unterstützen, wird aber in der C-Style-Definition "Vtbl" angezeigt.

Die Übergabe eines ungültigen Pointers kann zu undefiniertem Verhalten führen, inklusive (aber nicht beschränkt auf) Programmterminierung.

Typ1, Arg1

Typ: Zeichenkette

Jedes dieser Paare repräsentiert einen einzelnen Parameter, der an die Methode übergeben werden soll. Die Anzahl der Paare ist unbegrenzt. Geben Sie für Typ einen Typ aus der DllCall-Typentabelle an. Geben Sie für Arg einen Wert an, der an die Methode übergeben werden soll.

RückgabeTyp

Typ: Zeichenkette

Wenn weggelassen, wird standardmäßig HRESULT verwendet, was der häufigste Rückgabetyp für COM-Interface-Methoden ist. Jedes Ergebnis, das auf einen Fehler hinweist, bewirkt, dass ein OSError ausgelöst wird, daher darf der Rückgabetyp nur weggelassen werden, wenn der tatsächliche Rückgabetyp HRESULT ist.

Wenn die Methode vom Typ ist, der keinen Wert zurückgibt (der Rückgabetyp void in C), können Sie "Int" oder einen anderen numerischen Typ ohne Suffix (außer HRESULT) angeben und den Rückgabewert ignorieren. Da der Inhalt des Rückgabewertregisters in diesem Fall willkürlich ist, kann durch Weglassen von RückgabeTyp eine Ausnahme ausgelöst werden.

Andernfalls geben Sie einen der Argumenttypen aus der DllCall-Typentabelle an. Das Sternchen-Suffix wird ebenfalls unterstützt.

Obwohl ComCall das Schlüsselwort Cdecl gemäß DllCall unterstützt, wird es grundsätzlich nicht von COM-Interface-Methoden verwendet.

Rückgabewert

Typ: Zeichenkette oder Integer

Wenn RückgabeTyp HRESULT ist (oder weggelassen wird) und die Methode einen Fehlerwert (wie durch das FAILED-Makro definiert) zurückgegeben hat, wird ein OSError ausgelöst.

Andernfalls gibt ComCall den Rückgabewert der Methode zurück. Wenn die Methode vom Typ ist, der keinen Wert zurückgibt (mit einem Rückgabetyp, der in C als void definiert ist), ist das Ergebnis undefiniert und sollte ignoriert werden.

Bemerkungen

Die folgenden DllCall-Themen gelten auch für ComCall:

ComObject, ComObjQuery, ComValue, Buffer-Objekt, CallbackCreate

Beispiele

Entfernt das aktive Fenster für 3 Sekunden aus der Taskleiste. Äquivalent zum DllCall-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")

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

; Wenn das Objekt nicht mehr benötigt wird, einfach alle Referenzen mit
; einem anderen Wert ersetzen (oder return bei einer lokalen Variable):
tbl := ""

Zeigt einige Techniken zum Wrappen von COM-Interfaces. Äquivalent zum vorherigen Beispiel.

tbl := TaskbarList()

activeHwnd := WinExist("A")

tbl.DeleteTab(activeHwnd)
Sleep 3000
tbl.AddTab(activeHwnd)

tbl := ""


class TaskbarList {
    static IID := "{56FDF342-FD6D-11d0-958A-006097C9A090}"
    static CLSID := "{56FDF344-FD6D-11d0-958A-006097C9A090}"
    
    ; Wird beim Start aufgerufen, um die Klasse zu initialisieren.
    static __new() {
        ; Basisobjekt für alle Instanzen von TaskbarList abrufen.
        proto := this.Prototype
        
        ; Mit Bound-Funktionen können Parameter vordefiniert werden, wodurch die
        ; Methoden besser nutzbar werden, ohne Hilfe von Wrapper-Funktionen.
        ; HrInit selbst hat keine Parameter, also nur den Index binden,
        ; und der Aufrufer wird implizit 'this' übergeben.
        proto.HrInit := ComCall.Bind(3)
        
        ; Parameter leer lassen, um den Aufrufer einen Wert übergeben zu lassen.
        ; In diesem Fall ist der leere Parameter 'this' (i.d.R. versteckt).
        proto.AddTab := ComCall.Bind(4,, "ptr")
        
        ; Mit Object oder Map können Wiederholungen reduziert werden.
        for name, args in Map(
            "DeleteTab", [5,,"ptr"],
            "ActivateTab", [6,,"ptr"],
            "SetActiveAlt", [7,,"ptr"]) {
            proto.%name% := ComCall.Bind(args*)
        }
    }
    
    ; Wird bei einer neuen Instanz von TaskbarList() aufgerufen.
    __new() {
        this.comobj := ComObject(TaskbarList.CLSID, TaskbarList.IID)
        this.ptr := this.comobj.ptr
        ; Initialisierung via ITaskbarList anfordern.
        this.HrInit()
    }
}