Interface d'activation
La définition d'une interface d'activation personnalisée et son implémentation vont nous permettre de passer des arguments lors de la création d'un objet COM. Cet article montre comment créer une telle interface avec Delphi, et par suite le moyen d'implémenter le modèle de conception singleton en programmation COM.

Lorsque l'on crée un objet automation avec l'assistant de l'EDI Delphi, l'unité comprenant la déclaration de la nouvelle CoClasse, TTest par exemple, a, dans sa clause initialization, une instruction de la forme :

TAutoObjectFactory.Create(ComServer, TTest, Class_Test, ciMultiInstance, tmApartment);

Cette instruction crée au démarrage du serveur une instance de TAutoObjectFactory enregistrée comme étant l'usine de classe (ou fabrique d'objets) qui sert à créer des objets TTest. TAutoObjectFactory implémente en particulier l'interface COM IClassFactory.
Lorsqu'un client cherche à obtenir un pointeur d'interface sur un nouvel objet COM, que se soit par un appel indirect à CreateComObject ou par la fonction CreateOleObject, c'est la fonction de haut niveau CoCreateInstance de l'API Windows qui est appelé. Celle-ci détermine quel est le fabriquant de classe associé à l'objet demandé et obtient un pointeur d'interface IClassFactory de manière à invoquer sa méthode CreateInstance pour créer un nouvel objet.
Malheureusement il n'est pas possible de passer des arguments à CreateInstance pour avoir l'équivalent d'un constructeur de classe.
Le reste de cet article vous conduit pas à pas dans l'implémentation d'une interface personnalisée d'activation. Les codes source peuvent être obtenus dans la section Ressources en fin d'article.


Création d'un objet automation

Dans l'EDI Delphi, créez une nouvelle application Project1, puis ajouter un nouvel objet automation avec comme nom de CoClasse "Test". Nous enregistrons avec le nom Test l'unité générée par Delphi et comprenant la définition de la classe Test dérivée de TAutoObject et supportant l'interface ITest.
A des fins de test, nous définissons la propriété Message de type BSTR (WideString) pour l'interface ITest avec l'éditeur de la bibliothèque de types du projet. Nous nous contenterons de lire ou de modifier la variable privée FMessage de TTest.


Création et implémentation de l'interface personnalisée d'activation

Nous souhaitons définir une interface personnalisée nommée ITestFactory dont une des méthodes nous permettra d'instancier des objets TTest en lui passant une chaîne de caractères unicode en argument et renvoyant un pointeur d'interface ITest. En Pascal Objet :

function CreateTest(const Message: WideString): ITest; safecall;


Pour cela nous créons dans l'éditeur de la bibliothèque de types une nouvelle interface qui hérite de IUnknown et lui ajoutons la méthode décrite ci-dessus.
Il nous reste à définir la fabrique de classe supportant l'interface ITestFactory. Nous pouvons nous appuyer sur la classe TAutoObjectFactory :

TTestFactory = class(TAutoObjectFactory, ITestFactory)
protected
  function CreateTest(const Message: WideString): ITest; safecall;
end;

La méthode CreateTest se contente d'instancier un object TTest sous forme du pointeur d'interface ITest :

function TTestFactory.CreateTest(const Message: WideString): ITest;
begin
  Result := TTest.Create(Message) as ITest;
end;


Enregistrement de la fabrique de classe

Dans la clause initialization de l'unité Test, nous remplaçons l'instruction TAutoObjectFactory.Create(...) par TTestFactory.Create(...).
Cela a pour conséquence d'enregistrer TTestFactory comme fabrique de classe pour la classe TTest au lieu de TAutoObjectFactory qui aurait instancié des objets TTest à l'aide de IClassFactory.
Au démarrage du serveur, une instance de notre fabrique de classe est donc créée et enregistrée.


Accéder à la fabrique de classe

Une application cliente peut obtenir une référence vers l'instance enregistrée de la fabrique de classe du serveur à l'aide de la méthode GetObject définie dans l'unité ActivationObject.
Le serveur servant de test, Project1, doit bien sûr être recenser au préalable, soit en l'exécutant une première fois, soit en l'exécutant avec l'argument /regserver.
Cette fonction prend comme unique argument un GUID devant être celui de la classe pour laquelle celle-ci renvoie un fabriquant de classe. Dans notre exemple, c'est la constante CLASS_Test de la bibliothèque de types. GetObject renvoie une référence IUnknown qui peut ensuite être transtypée en ITestFactory à l'aide de l'opérateur as.
Le programme de test, Project1, du répertoire Client utilise donc la fabrique de classe de TTest pour instancier un objet TTest avec la méthode ITestFactory.CreateTest, de la manière suivante :

var
  TestFactory: ITestFactory;
begin
  TestFactory := GetObject(CLASS_Test) as ITestFactory;
  Test := TestFactory.CreateTest(Edit1.Text); // Test est de type ITest
end;

La fonction GetObject (nom d'une fonction équivalente en Visual Basic) est implémentée un utilisant un moniker de classe. La description des monikers déborde du cadre de cet article.


Singleton COM

L'utilisation d'une interface personnalisée d'activation permet l'implémentation du modèle de conception singleton en programmation COM. En effet, une fonction telle que CreateTest pourrait toujours renvoyer la même instance d'objet créée une seule fois dans le fabriquant de classe, au premier appel de cette méthode.


Ressources

Téléchargez les programmes d'exemple

Sommaire

Création d'un objet automation
Création et implémentation de l'interface personnalisée d'activation
Enregistrement de la fabrique de classe
Accéder à la fabrique de classe
Singleton COM
Ressources

Début

Copyright © 2003 OBJECT-EVERYWHERE. Tous droits réservés | Bertrand Goetzmann