Udostępnij przez


Korzystanie z narzędzia CUnknown

[Funkcja skojarzona z tą stroną, DirectShow, jest starszą funkcją. Zostało zastąpione przez MediaPlayer, IMFMediaEnginei Audio/Video Capture w Media Foundation. Te funkcje zostały zoptymalizowane pod kątem systemów Windows 10 i Windows 11. Firma Microsoft zdecydowanie zaleca, aby nowy kod używał MediaPlayer, IMFMediaEngine i Audio/Video Capture w programie Media Foundation zamiast DirectShow, jeśli to możliwe. Firma Microsoft sugeruje, że istniejący kod, który używa starszych interfejsów API, należy przepisać go do korzystania z nowych interfejsów API, jeśli to możliwe.]

DirectShow implementuje IUnknown w klasie bazowej o nazwie CUnknown. Można użyć CUnknown do tworzenia innych klas, przesłaniając tylko te metody, które różnią się między komponentami. Większość innych klas bazowych w DirectShow wywodzi się od CUnknown, więc składnik może dziedziczyć bezpośrednio z CUnknown lub innej klasy bazowej.

INonDelegatingUnknown

CUnknown implementuje INonDelegatingUnknown. Zarządza wewnętrznie licznikami odwołań, a w większości przypadków klasa pochodna może bez zmian dziedziczyć obie metody zliczania odwołań. Należy pamiętać, że CUnknown usuwa się, gdy liczba odwołań spadnie do zera. Z drugiej strony należy zastąpić CUnknown::NonDelegatingQueryInterface, ponieważ metoda w klasie bazowej zwraca E_NOINTERFACE, jeśli otrzymuje jakikolwiek identyfikator IID inny niż IID_IUnknown. W klasie pochodnej przetestuj identyfikatory IID interfejsów, które obsługujesz, jak pokazano w poniższym przykładzie:

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);
}

Funkcja pomocnicza GetInterface (zobacz Funkcje Pomocnicze COM) ustawia wskaźnik, zwiększa liczbę odwołań w sposób bezpieczny dla wątków i zwraca S_OK. W domyślnym przypadku wywołaj metodę klasy bazowej i zwróć wynik. Jeśli pochodzisz z innej klasy bazowej, wywołaj jej metodę NonDelegatingQueryInterface. Dzięki temu można obsługiwać wszystkie interfejsy obsługiwane przez klasę nadrzędną.

IUnknown

Jak wspomniano wcześniej, wersja delegująca IUnknown jest taka sama dla każdego składnika, ponieważ robi nic więcej niż wywoływanie poprawnego wystąpienia wersji niedelegującej. Dla wygody plik nagłówkowy Combase.h zawiera makro, DECLARE_IUNKNOWN, który deklaruje trzy metody delegowania jako metody wbudowane. Rozwija się do następującego kodu:

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

Funkcja użytkowa CUnknown::GetOwner pobiera wskaźnik do interfejsu IUnknown składnika, który jest właścicielem tego komponentu. W przypadku składnika zagregowanego właściciel jest składnikiem zewnętrznym. W przeciwnym razie składnik jest właścicielem samego siebie. Uwzględnij makro DECLARE_IUNKNOWN w publicznej sekcji definicji klasy.

Konstruktor klasy

Konstruktor twojej klasy powinien wywołać metodę konstruktora dla klasy nadrzędnej, a także wykonywać czynności specyficzne dla twojej klasy. Poniższy przykład to typowa metoda konstruktora:

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

Metoda przyjmuje następujące parametry, które przekazuje bezpośrednio do metody konstruktora CUnknown.

  • tszName określa nazwę składnika.
  • pUnk to wskaźnik do agregującego IUnknown.
  • pHr jest wskaźnikiem wartości HRESULT wskazującym powodzenie lub niepowodzenie metody.

Streszczenie

W poniższym przykładzie przedstawiono klasę pochodną, która obsługuje IUnknown i hipotetyczny interfejs o nazwie 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.
};

W tym przykładzie przedstawiono następujące kwestie:

  • Klasa CUnknown implementuje interfejs IUnknown. Nowy składnik dziedziczy z CUnknown i z dowolnych interfejsów, które obsługuje składnik. Składnik może pochodzić zamiast tego z innej klasy bazowej dziedziczonej z CUnknown.
  • Makro DECLARE_IUNKNOWN deklaruje delegowanie metod IUnknown jako metod wbudowanych.
  • Klasa CUnknown udostępnia implementację INonDelegatingUnknown.
  • Aby obsługiwać interfejs inny niż IUnknown, klasa pochodna musi zastąpić metodę NonDelegatingQueryInterface i przetestować identyfikator IID nowego interfejsu.
  • Konstruktor klasy wywołuje metodę konstruktora dla CUnknown.

Następnym krokiem pisania filtru jest umożliwienie aplikacji tworzenia nowych wystąpień składnika. Wymaga to zrozumienia bibliotek DLL i ich relacji z fabrykami klas i metodami konstruktora klas. Aby uzyskać więcej informacji, zobacz Jak stworzyć filtr DirectShow w formacie DLL.

Jak zaimplementować IUnknown