Fonctionnement de IUnknown

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

Nombre de références

Le décompte 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 décompte de références et synchronisent l’accès au décompte 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. Dans le cas contraire, elle définit le pointeur sur la valeur null et retourne E _ nointerface. Le pseudo-code suivant illustre la structure générale de la méthode QueryInterface . L’agrégation de composants, décrite dans la section suivante, présente 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’une autre est la liste des IID que chaque composant teste. Pour chaque interface que le composant prend en charge, 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 seule interface IUnknown , le composant agrégé reportant à l’implémentation du composant externe. Dans le cas contraire, l’appelant voit 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 opération IUnknown de délégation délègue le travail à l’emplacement approprié : au composant externe, s’il y en a un, ou à la version interne du composant. Une Nondelegating IUnknown 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 nondelegating 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 dans la délégation IUnknown appelle son équivalent nondelegating, comme indiqué dans l’exemple suivant :

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

Par la nature de la délégation, les méthodes de délégation semblent identiques dans chaque composant. Seules les versions de nondelegating changent.

Comment implémenter IUnknown