Freigeben über


Funktionsweise von IUnknown

[Das dieser Seite zugeordnete Feature DirectShow ist ein Legacyfeature. Es wurde von MediaPlayer, IMFMediaEngine und Audio/Video Capture in Media Foundation abgelöst. Diese Features wurden für Windows 10 und Windows 11 optimiert. Microsoft empfiehlt dringend, dass neuer Code mediaPlayer, IMFMediaEngine und Audio/Video Capture in Media Foundation anstelle von DirectShow verwendet, wenn möglich. Microsoft schlägt vor, dass vorhandener Code, der die Legacy-APIs verwendet, so umgeschrieben wird, dass nach Möglichkeit die neuen APIs verwendet werden.]

Die Methoden in IUnknown ermöglichen es einer Anwendung, Schnittstellen für die Komponente abzufragen und die Verweisanzahl der Komponente zu verwalten.

Verweisanzahl

Die Verweisanzahl ist eine interne Variable, die in der AddRef-Methode inkrementiert und in der Release-Methode verringert wird. Die Basisklassen verwalten die Verweisanzahl und synchronisieren den Zugriff auf die Verweisanzahl zwischen mehreren Threads.

Schnittstellenabfragen

Das Abfragen einer Schnittstelle ist ebenfalls einfach. Der Aufrufer übergibt zwei Parameter: einen Schnittstellenbezeichner (Interface Identifier, IID) und die Adresse eines Zeigers. Wenn die Komponente die angeforderte Schnittstelle unterstützt, legt sie den Zeiger auf die Schnittstelle fest, erhöht ihre eigene Verweisanzahl und gibt S_OK zurück. Andernfalls wird der Zeiger auf NULL festgelegt und E_NOINTERFACE zurückgegeben. Der folgende Pseudocode zeigt die allgemeine Gliederung der QueryInterface-Methode . Die Komponentenaggregation, die im nächsten Abschnitt beschrieben wird, führt zu einer zusätzlichen Komplexität.

if (IID == IID_IUnknown)
    set pointer to (IUnknown *)this
    AddRef
    return S_OK

else if (IID == IID_ISomeInterface)
    set pointer to (ISomeInterface *)this
    AddRef
    return S_OK

else if ... 

else
    set pointer to NULL
    return E_NOINTERFACE

Der einzige Unterschied zwischen der QueryInterface-Methode einer Komponente und der QueryInterface-Methode einer anderen ist die Liste der IIDs, die jede Komponente testet. Für jede Schnittstelle, die von der Komponente unterstützt wird, muss die Komponente auf die IID dieser Schnittstelle testen.

Aggregation und Delegierung

Die Komponentenaggregation muss für den Aufrufer transparent sein. Daher muss das Aggregat eine einzelne IUnknown-Schnittstelle verfügbar machen, wobei die aggregierte Komponente auf die Implementierung der äußeren Komponente verschoben wird. Andernfalls würde der Aufrufer zwei verschiedene IUnknown-Schnittstellen im selben Aggregat sehen. Wenn die Komponente nicht aggregiert ist, verwendet sie eine eigene Implementierung.

Um dieses Verhalten zu unterstützen, muss die Komponente eine Dereferenzierungsebene hinzufügen. Ein delegierender IUnknown delegiert die Arbeit an die geeignete Stelle: an die äußere Komponente, falls vorhanden, oder an die interne Version der Komponente. Ein nicht delegierender IUnknown übernimmt die Arbeit, wie im vorherigen Abschnitt beschrieben.

Die delegierende Version ist öffentlich und behält den Namen IUnknown bei. Die nicht delegierende Version wird in INonDelegatingUnknown umbenannt. Dieser Name ist nicht Teil der COM-Spezifikation, da es sich nicht um eine öffentliche Schnittstelle handelt.

Wenn der Client eine instance der Komponente erstellt, ruft er die IClassFactory::CreateInstance-Methode auf. Ein Parameter ist ein Zeiger auf die IUnknown-Schnittstelle der Aggregierungskomponente oder NULL, wenn die neue instance nicht aggregiert ist. Die Komponente verwendet diesen Parameter, um eine Membervariable zu speichern, die angibt, welche IUnknown-Schnittstelle verwendet werden soll, wie im folgenden Beispiel gezeigt:

CMyComponent::CMyComponent(IUnknown *pOuterUnkown)
{
    if (pOuterUnknown == NULL)
        m_pUnknown = (IUnknown *)(INonDelegatingUnknown *)this;
    else
        m_pUnknown = pOuterUnknown;

    [ ... more constructor code ... ]
}

Jede Methode in der delegierenden IUnknown ruft ihre nicht delegierende Entsprechung auf, wie im folgenden Beispiel gezeigt:

HRESULT QueryInterface(REFIID iid, void **ppv) 
{
    return m_pUnknown->QueryInterface(iid, ppv);
}

Aufgrund der Art der Delegierung sehen die Delegierungsmethoden in jeder Komponente identisch aus. Nur die nicht delegierenden Versionen ändern sich.

Implementieren von IUnknown