Fonctionnement d’IUnknown

[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.]

Les méthodes dans IUnknown permettent à une application d’interroger des interfaces sur le composant et de gérer le nombre de références du composant.

Nombre de références

Le nombre de références est une variable interne, incrémentée dans la méthode AddRef et décrémentée dans la méthode Release . Les classes de base gèrent le nombre de références et synchronisent l’accès au nombre de références entre plusieurs threads.

Requêtes d’interface

L’interrogation d’une interface est également simple. L’appelant passe deux paramètres : un identificateur d’interface (IID) et l’adresse d’un pointeur. Si le composant prend en charge l’interface demandée, il définit le pointeur sur l’interface, incrémente son propre nombre de références et retourne S_OK. Sinon, il définit le pointeur sur NULL et retourne E_NOINTERFACE. Le pseudocode suivant présente le contour général de la méthode QueryInterface . L’agrégation de composants, décrite dans la section suivante, introduit une complexité supplémentaire.

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

La seule différence entre la méthode QueryInterface d’un composant et la méthode QueryInterface d’un autre est la liste des ID DEI que chaque composant teste. Pour chaque interface prise en charge par le composant, le composant doit tester l’IID de cette interface.

Agrégation et délégation

L’agrégation de composants doit être transparente pour l’appelant. Par conséquent, l’agrégat doit exposer une interface IUnknown unique, le composant agrégé se reportant à l’implémentation du composant externe. Sinon, l’appelant verrait deux interfaces IUnknown différentes dans le même agrégat. Si le composant n’est pas agrégé, il utilise sa propre implémentation.

Pour prendre en charge ce comportement, le composant doit ajouter un niveau d’indirection. Une délégation IUnknown délègue le travail à l’emplacement approprié : au composant externe, le cas échéant, ou à la version interne du composant. Un IUnknown sans suppression effectue le travail, comme décrit dans la section précédente.

La version de délégation est publique et conserve le nom IUnknown. La version sans suppression est renommée INonDelegatingUnknown. Ce nom ne fait pas partie de la spécification COM, car il ne s’agit pas d’une interface publique.

Lorsque le client crée une instance du composant, il appelle la méthode IClassFactory::CreateInstance. Un paramètre est un pointeur vers l’interface IUnknown du composant d’agrégation, ou NULL si la nouvelle instance n’est pas agrégée. Le composant utilise ce paramètre pour stocker une variable membre indiquant l’interface IUnknown à utiliser, comme illustré dans l’exemple suivant :

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

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

Chaque méthode de la délégation D’IUnknown appelle son équivalent sans suppression, comme illustré dans l’exemple suivant :

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

De par la nature de la délégation, les méthodes de délégation sont identiques dans chaque composant. Seules les versions qui ne sont pas en cours de suppression changent.

Comment implémenter IUnknown