Utilisation de CUnknown

[La fonctionnalité associée à cette page, DirectShow, est une fonctionnalité héritée. Il a été remplacé par MediaPlayer, IMFMediaEngine et Audio/Video Capture dans Media Foundation. Ces fonctionnalités ont été optimisées pour Windows 10 et Windows 11. Microsoft recommande vivement au nouveau code d’utiliser MediaPlayer, IMFMediaEngine et La capture audio/vidéo dans Media Foundation au lieu de DirectShow, lorsque cela est possible. Microsoft suggère que le code existant qui utilise les API héritées soit réécrit pour utiliser les nouvelles API si possible.]

DirectShow implémente IUnknown dans une classe de base appelée CUnknown. Vous pouvez utiliser CUnknown pour dériver d’autres classes, en remplaçant uniquement les méthodes qui changent d’un composant à l’autre. La plupart des autres classes de base dans DirectShow dérivent de CUnknown, de sorte que votre composant peut hériter directement de CUnknown ou d’une autre classe de base.

INonDelegatingUnknown

CUnknown implémente INonDelegatingUnknown. Il gère les nombres de références en interne et, dans la plupart des cas, votre classe dérivée peut hériter des deux méthodes de comptage des références sans aucune modification. N’oubliez pas que CUnknown se supprime lui-même lorsque le nombre de références tombe à zéro. En revanche, vous devez remplacer CUnknown::NonDelegatingQueryInterface, car la méthode de la classe de base retourne E_NOINTERFACE si elle reçoit un IID autre que IID_IUnknown. Dans votre classe dérivée, testez les ID d’interfaces que vous prenez en charge, comme illustré dans l’exemple suivant :

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

La fonction d’utilitaire GetInterface (voir Fonctions COM Helper) définit le pointeur, incrémente le nombre de références de manière thread-safe et retourne S_OK. Dans le cas par défaut, appelez la méthode de classe de base et retournez le résultat. Si vous dérivez d’une autre classe de base, appelez plutôt sa méthode NonDelegatingQueryInterface . Cela vous permet de prendre en charge toutes les interfaces prises en charge par la classe parente.

IUnknown

Comme mentionné précédemment, la version de délégation d’IUnknown est la même pour chaque composant, car elle ne fait rien d’autre qu’appeler la instance correcte de la version qui n’est pas en cours de suppression. Pour des raisons pratiques, le fichier d’en-tête Combase.h contient une macro, DECLARE_IUNKNOWN, qui déclare les trois méthodes de délégation en tant que méthodes inline. Il se développe jusqu’au code suivant :

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

La fonction utilitaire CUnknown::GetOwner récupère un pointeur vers l’interface IUnknown du composant propriétaire de ce composant. Pour un composant agrégé, le propriétaire est le composant externe. Sinon, le composant est propriétaire de lui-même. Incluez la macro DECLARE_IUNKNOWN dans la section publique de votre définition de classe.

Constructeur de classe

Votre constructeur de classe doit appeler la méthode du constructeur pour la classe parente, en plus de tout ce qu’il fait qui est spécifique à votre classe. L’exemple suivant est une méthode de constructeur classique :

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

La méthode prend les paramètres suivants, qu’elle transmet directement à la méthode du constructeur CUnknown .

  • tszName spécifie un nom pour le composant.
  • pUnk est un pointeur vers l’agrégation IUnknown.
  • pHr est un pointeur vers une valeur HRESULT, indiquant la réussite ou l’échec de la méthode.

Résumé

L’exemple suivant montre une classe dérivée qui prend en charge IUnknown et une interface hypothétique nommée 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.
};

Cet exemple illustre les points suivants :

  • La classe CUnknown implémente l’interface IUnknown . Le nouveau composant hérite de CUnknown et de toutes les interfaces prises en charge par le composant. Le composant peut dériver à la place d’une autre classe de base qui hérite de CUnknown.
  • La macro DECLARE_IUNKNOWN déclare les méthodes IUnknown de délégation en tant que méthodes inline.
  • La classe CUnknown fournit l’implémentation pour INonDelegatingUnknown.
  • Pour prendre en charge une interface autre que IUnknown, la classe dérivée doit remplacer la méthode NonDelegatingQueryInterface et tester l’IID de la nouvelle interface.
  • Le constructeur de classe appelle la méthode du constructeur pour CUnknown.

L’étape suivante dans l’écriture d’un filtre consiste à permettre à une application de créer de nouvelles instances du composant. Cela nécessite une compréhension des DLL et de leur relation avec les fabriques de classes et les méthodes de constructeur de classe. Pour plus d’informations, consultez Création d’une DLL de filtre DirectShow.

Comment implémenter IUnknown