Freigeben über


Verwenden von CUnknown

[Das dieser Seite zugeordnete Feature DirectShow ist ein Legacyfeature. Es wurde durch MediaPlayer, IMFMediaEngine und Audio/Video Capture in Media Foundation ersetzt. Diese Features wurden für Windows 10 und Windows 11 optimiert. Microsoft empfiehlt dringend, dass neuer Code nach Möglichkeit MediaPlayer, IMFMediaEngine und Audio/Video Capture in Media Foundation anstelle von DirectShow verwendet. Microsoft schlägt vor, vorhandenen Code, der die Legacy-APIs verwendet, um nach Möglichkeit die neuen APIs zu verwenden.]

DirectShow implementiert IUnknown in einer Basisklasse namens CUnknown. Sie können CUnknown verwenden, um andere Klassen abzuleiten und dabei nur die Methoden zu überschreiben, die sich komponentenübergreifend ändern. Die meisten anderen Basisklassen in DirectShow leiten von CUnknown ab, sodass Ihre Komponente direkt von CUnknown oder einer anderen Basisklasse erben kann.

INonDelegatingUnknown

CUnknown implementiert INonDelegatingUnknown. Sie verwaltet die Verweisanzahl intern, und in den meisten Fällen kann Ihre abgeleitete Klasse die beiden Verweiszählungsmethoden ohne Änderung erben. Beachten Sie, dass CUnknown sich selbst löscht, wenn die Verweisanzahl auf 0 sinkt. Andererseits müssen Sie CUnknown::NonDelegatingQueryInterface überschreiben, da die Methode in der Basisklasse E_NOINTERFACE zurückgibt, wenn sie eine andere IID als IID_IUnknown empfängt. Testen Sie in Ihrer abgeleiteten Klasse auf die IIDs von Schnittstellen, die Sie unterstützen, wie im folgenden Beispiel gezeigt:

STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv)
{
    if (riid == IID_ISomeInterface)
    {
        return GetInterface((ISomeInterface*)this, ppv);
    }
    // Default: Call parent class method. 
    // The CUnknown class must be in the inheritance chain.
    return CParentClass::NonDelegatingQueryInterface(riid, ppv);
}

Die Hilfsprogrammfunktion GetInterface (siehe COM-Hilfsfunktionen) legt den Zeiger fest, erhöht die Verweisanzahl auf threadsichere Weise und gibt S_OK zurück. Rufen Sie im Standardfall die Basisklassenmethode auf, und geben Sie das Ergebnis zurück. Wenn Sie von einer anderen Basisklasse abgeleitet werden, rufen Sie stattdessen die NonDelegatingQueryInterface-Methode auf. Dadurch können Sie alle Schnittstellen unterstützen, die die übergeordnete Klasse unterstützt.

IUnknown

Wie bereits erwähnt, ist die delegierende Version von IUnknown für jede Komponente identisch, da sie nichts anderes als den richtigen instance der nicht delegierenden Version aufruft. Der Einfachheit halber enthält die Headerdatei Combase.h ein Makro, DECLARE_IUNKNOWN, das die drei delegierenden Methoden als Inlinemethoden deklariert. Sie wird auf den folgenden Code erweitert:

STDMETHODIMP QueryInterface(REFIID riid, void **ppv) {      
    return GetOwner()->QueryInterface(riid,ppv);            
};                                                          
STDMETHODIMP_(ULONG) AddRef() {                             
    return GetOwner()->AddRef();                            
};                                                          
STDMETHODIMP_(ULONG) Release() {                            
    return GetOwner()->Release();                           
};

Die Hilfsprogrammfunktion CUnknown::GetOwner ruft einen Zeiger auf die IUnknown-Schnittstelle der Komponente ab, die diese Komponente besitzt. Bei einer aggregierten Komponente ist der Besitzer die äußere Komponente. Andernfalls besitzt die Komponente sich selbst. Fügen Sie das Makro DECLARE_IUNKNOWN in den öffentlichen Abschnitt Ihrer Klassendefinition ein.

Klassenkonstruktor

Ihr Klassenkonstruktor sollte die Konstruktormethode für die übergeordnete Klasse aufrufen, zusätzlich zu allen Aktionen, die für Ihre Klasse spezifisch sind. Das folgende Beispiel ist eine typische Konstruktormethode:

CMyComponent(TCHAR *tszName, LPUNKNOWN pUnk, HRESULT *phr) 
    : CUnknown(tszName, pUnk, phr)
{ 
    /* Other initializations */ 
};

Die -Methode übernimmt die folgenden Parameter, die sie direkt an die CUnknown-Konstruktormethode übergibt.

  • tszName gibt einen Namen für die Komponente an.
  • pUnk ist ein Zeiger auf das aggregierende IUnknown.
  • pHr ist ein Zeiger auf einen HRESULT-Wert, der den Erfolg oder Fehler der Methode angibt.

Zusammenfassung

Das folgende Beispiel zeigt eine abgeleitete Klasse, die IUnknown unterstützt, und eine hypothetische Schnittstelle mit dem Namen ISomeInterface:

class CMyComponent : public CUnknown, public ISomeInterface
{
public:

    DECLARE_IUNKNOWN;

    STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv)
    {
        if( riid == IID_ISomeInterface )
        {
            return GetInterface((ISomeInterface*)this, ppv);
        }
        return CUnknown::NonDelegatingQueryInterface(riid, ppv);
    }

    CMyComponent(TCHAR *tszName, LPUNKNOWN pUnk, HRESULT *phr) 
        : CUnknown(tszName, pUnk, phr)
    { 
        /* Other initializations */ 
    };

    // More declarations will be added later.
};

In diesem Beispiel werden die folgenden Punkte veranschaulicht:

Der nächste Schritt beim Schreiben eines Filters besteht darin, einer Anwendung das Erstellen neuer Instanzen der Komponente zu ermöglichen. Dies erfordert ein Verständnis von DLLs und ihrer Beziehung zu Klassenfabriken und Klassenkonstruktormethoden. Weitere Informationen finden Sie unter Erstellen einer DirectShow-Filter-DLL.

Implementieren von IUnknown