Création d’un objet dans COM

Une fois qu’un thread a initialisé la bibliothèque COM, il est sécurisé pour le thread d’utiliser des interfaces COM. Pour utiliser une interface COM, votre programme crée d’abord une instance d’un objet qui implémente cette interface.

En général, il existe deux façons de créer un objet COM :

  • Le module qui implémente l’objet peut fournir une fonction spécifiquement conçue pour créer des instances de cet objet.
  • Com fournit également une fonction de création générique nommée CoCreateInstance.

Par exemple, prenez l’objet hypothétique Shape de la rubrique Qu’est-ce qu’une interface COM ?. Dans cet exemple, l’objet Shape implémente une interface nommée IDrawable. La bibliothèque graphique qui implémente l’objet Shape peut exporter une fonction avec la signature suivante.

// Not an actual Windows function. 

HRESULT CreateShape(IDrawable** ppShape);

Compte tenu de cette fonction, vous pouvez créer un objet Shape comme suit.

IDrawable *pShape;

HRESULT hr = CreateShape(&pShape);
if (SUCCEEDED(hr))
{
    // Use the Shape object.
}
else
{
    // An error occurred.
}

Le paramètre ppShape est de type pointeur vers pointeur versIDrawable. Si vous n’avez pas vu ce modèle auparavant, la double indirection peut être déroutante.

Tenez compte des exigences de la CreateShape fonction. La fonction doit renvoyer un IDrawable pointeur vers l’appelant. Mais la valeur de retour de la fonction est déjà utilisée pour le code d’erreur/réussite. Par conséquent, le pointeur doit être retourné via un argument à la fonction . L’appelant passe une variable de type IDrawable* à la fonction, et la fonction remplace cette variable par un nouveau IDrawable pointeur. En C++, il existe seulement deux façons pour une fonction de remplacer une valeur de paramètre : passer par référence ou passer par adresse. COM utilise ce dernier, pass-by-address. L’adresse d’un pointeur étant un pointeur vers un pointeur, le type de paramètre doit être IDrawable**.

Voici un diagramme pour vous aider à visualiser ce qui se passe.

diagramme montrant l’indirection de double pointeur

La CreateShape fonction utilise l’adresse de pShape (&pShape) pour écrire une nouvelle valeur de pointeur vers pShape.

CoCreateInstance : une méthode générique pour créer des objets

La fonction CoCreateInstance fournit un mécanisme générique pour créer des objets. Pour comprendre CoCreateInstance, gardez à l’esprit que deux objets COM peuvent implémenter la même interface et un objet peut implémenter deux interfaces ou plus. Ainsi, une fonction générique qui crée des objets a besoin de deux informations.

  • Objet à créer.
  • Interface à obtenir à partir de l’objet .

Mais comment indiquer ces informations quand nous appelons la fonction ? Dans COM, un objet ou une interface est identifié en lui affectant un nombre de 128 bits, appelé identificateur global unique (GUID). Les GUID sont générés d’une manière qui les rend effectivement uniques. Les GUID sont une solution au problème de création d’identificateurs uniques sans autorité d’inscription centrale. Les GUID sont parfois appelés identificateurs uniques universels (UUID). Avant COM, ils étaient utilisés dans DCE/RPC (Distributed Computing Environment/Remote Procedure Call). Plusieurs algorithmes existent pour créer de nouveaux GUID. Tous ces algorithmes ne garantissent pas strictement l’unicité, mais la probabilité de créer accidentellement deux fois la même valeur GUID est extrêmement faible , en fait zéro. Les GUID peuvent être utilisés pour identifier n’importe quel type d’entité, et pas seulement des objets et des interfaces. Toutefois, c’est la seule utilisation qui nous concerne dans ce module.

Par exemple, la Shapes bibliothèque peut déclarer deux constantes GUID :

extern const GUID CLSID_Shape;
extern const GUID IID_IDrawable; 

(Vous pouvez supposer que les valeurs numériques 128 bits réelles pour ces constantes sont définies ailleurs.) La constante CLSID_Shape identifie l’objet Shape , tandis que la constante IID_IDrawable identifie l’interface IDrawable . Le préfixe « CLSID » correspond à l’identificateur de classe et le préfixe IID correspond à l’identificateur d’interface. Il s’agit de conventions de nommage standard dans COM.

Compte tenu de ces valeurs, vous devez créer une Shape instance comme suit :

IDrawable *pShape;
hr = CoCreateInstance(CLSID_Shape, NULL, CLSCTX_INPROC_SERVER, IID_IDrawable,
     reinterpret_cast<void**>(&pShape));

if (SUCCEEDED(hr))
{
    // Use the Shape object.
}
else
{
    // An error occurred.
}

La fonction CoCreateInstance a cinq paramètres. Les premier et quatrième paramètres sont l’identificateur de classe et l’identificateur d’interface. En effet, ces paramètres indiquent à la fonction : « Créez l’objet Shape et donnez-moi un pointeur vers l’interface IDrawable ».

Définissez le deuxième paramètre sur NULL. (Pour plus d’informations sur la signification de ce paramètre, consultez la rubrique Agrégation dans la documentation COM.) Le troisième paramètre prend un ensemble d’indicateurs dont main objectif est de spécifier le contexte d’exécution de l’objet. Le contexte d’exécution spécifie si l’objet s’exécute dans le même processus que l’application ; dans un autre processus sur le même ordinateur ; ou sur un ordinateur distant. Le tableau suivant montre les valeurs les plus courantes pour ce paramètre.

Indicateur Description
CLSCTX_INPROC_SERVER Même processus.
CLSCTX_LOCAL_SERVER Processus différent, même ordinateur.
CLSCTX_REMOTE_SERVER Ordinateur différent.
CLSCTX_ALL Utilisez l’option la plus efficace prise en charge par l’objet. (Le classement, du plus efficace au moins efficace, est : in-process, out-of-process et cross-computer.)

 

La documentation d’un composant particulier peut vous indiquer le contexte d’exécution pris en charge par l’objet. Si ce n’est pas le cas, utilisez CLSCTX_ALL. Si vous demandez un contexte d’exécution que l’objet ne prend pas en charge, la fonction CoCreateInstance retourne le code d’erreur REGDB_E_CLASSNOTREG. Ce code d’erreur peut également indiquer que le CLSID ne correspond à aucun composant inscrit sur l’ordinateur de l’utilisateur.

Le cinquième paramètre de CoCreateInstance reçoit un pointeur vers l’interface. Étant donné que CoCreateInstance est un mécanisme générique, ce paramètre ne peut pas être fortement typé. Au lieu de cela, le type de données est void**, et l’appelant doit forcer l’adresse du pointeur vers un type void** . C’est l’objectif de l’reinterpret_cast dans l’exemple précédent.

Il est essentiel de case activée la valeur de retour de CoCreateInstance. Si la fonction retourne un code d’erreur, le pointeur d’interface COM n’est pas valide et si vous tentez de le déréférencer, votre programme peut se bloquer.

En interne, la fonction CoCreateInstance utilise différentes techniques pour créer un objet. Dans le cas le plus simple, il recherche l’identificateur de classe dans le Registre. L’entrée du Registre pointe vers une DLL ou EXE qui implémente l’objet. CoCreateInstance peut également utiliser des informations provenant d’un catalogue COM+ ou d’un manifeste côte à côte (SxS). Quoi qu’il en soit, les détails sont transparents pour l’appelant. Pour plus d’informations sur les détails internes de CoCreateInstance, consultez Clients et serveurs COM.

L’exemple Shapes que nous avons utilisé est quelque peu artificiel. Nous allons donc maintenant nous tourner vers un exemple réel de COM en action : affichant la boîte de dialogue Ouvrir pour que l’utilisateur sélectionne un fichier.

Suivant

Exemple : boîte de dialogue Ouvrir