Verwenden von CUnknown

DirectShow implementiert IUnknown in einer Basisklasse namens CUnknown. Sie können CUnknown verwenden, um andere Klassen ableiten und dabei nur die Methoden außer Kraft zu setzen, die sich komponentenübergreifend ändern. Die meisten anderen Basisklassen in DirectShow sind von CUnknown ableiten, sodass Ihre Komponente direkt von CUnknown oder von einer anderen Basisklasse erben kann.

INonDelegatingUnknown

CUnknown implementiert INonDelegatingUnknown. Die Verweisanzahl wird intern verwaltet, und in den meisten Situationen kann Ihre abgeleitete Klasse die beiden Verweiszählungsmethoden ohne Änderung erben. Beachten Sie, dass CUnknown sich selbst löscht, wenn der Verweiszähler auf 0 (null) fällt. 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 der 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 Hilfsfunktion GetInterface (siehe COM-Hilfsfunktionen) legt den Zeiger fest, erhöht die Verweisanzahl threadsicher 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 ableiten, rufen Sie stattdessen deren NonDelegatingQueryInterface-Methode auf. Dadurch können Sie alle Schnittstellen unterstützen, die von der übergeordneten Klasse unterstützt werden.

IUnknown

Wie bereits erwähnt, ist die delegierende Version von IUnknown für jede Komponente identisch, da sie nur die richtige Instanz der nicht delegierenden Version aufruft. Der Einfachheit halber enthält die Headerdatei Combase.h das Makro DECLARE _ IUNKNOWN,das die drei delegierenden Methoden als Inlinemethoden deklariert. Er 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 Hilfsfunktion 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 sich die Komponente selbst. Schließen Sie das DECLARE _ IUNKNOWN-Makro in den öffentlichen Abschnitt Ihrer Klassendefinition ein.

Klassenkonstruktor

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

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

Die -Methode verwendet 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 die 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 namens 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 im Aktivieren einer Anwendung zum Erstellen neuer Instanzen der Komponente. Dies erfordert ein Verständnis von DLLs und ihrer Beziehung zu Klassen factorys und Klassenkonstruktormethoden. Weitere Informationen finden Sie unter Erstellen einer DirectShow-Filter-DLL.

Implementieren von IUnknown