Institut numerique

2.4 Principes fondamentaux de COM

COM définit plusieurs concepts fondamentaux qui fournissent les fondements structuraux du modèle. Ceux-ci incluent [MIC 11] :

 Un standard binaire pour la fonction d‟appel entre les composants.

 Une interface de base fournissant :

 Une manière pour que les composants découvrent dynamiquement les interfaces mises en application par d’autres composants.

 Mettre en référence le compte pour permettre à des composants de gérer leur propre vie.

 Un mécanisme pour identifier les composants et leurs interfaces de manière unique, dans le monde entier.

Dans les sections suivantes nous allons présenter les concepts de base en détail du modèle COM, et qui sont nécessaires pour la création des composants COM.

2.4.1 Standard Binaire

Pour n’importe quelle plateforme donnée (combinaison de matériel et de système d’exploitation), COM définit une manière standard pour présenter les tables virtuelles de fonction « vtable (Virtuel table) » dans la mémoire, et une manière standard d’appeler les fonctions par les vtables.

Ainsi, n’importe quelle langage qui peut appeler des fonctions par l’intermédiaire des pointeurs (C, C++, Smalltalk, ADA, et même BASIC), tout peut être utilisé pour écrire les composants qui peuvent interopérer avec d’autres composants écrits suivant le même standard binaire.

L’adressage indirect (le client tient un pointeur sur un vtable) tient compte de la mise en commun de vtable entre des instances multiples de la même classe d’objet. Sur un système avec centaines instances d’objet, le partage vtable peut réduire considérablement les demandes de mémoire, parce que les vtables additionnels se dirigeant à la même instance de composant, et donc consomment beaucoup moins de mémoire que des instances multiples du même composant [MIC 11].


Figure 2.2 Tables virtuelles de fonctions (VTBL).

2.4.2 Objets et Composants COM

Le mot objet tend à signifier quelque chose de différent pour chacun. Pour clarifier: Dans COM, un objet est un morceau de code compilé qui fournit un certain service au reste du système.

Pour éviter la confusion, il est probablement le meilleur pour se rapporter à un objet utilisé dans COM comme composant COM ou simplement comme composant. Ceci évite de confondre les composants COM avec des objets du code source de la POO (Programmation orienté objet).

Les composants COM soutiennent une interface de base appelée IUnknown (décrite plus tard), avec une combinaison d’autres interfaces, dépendant de fonctionnalité que le composant COM choisit d’exposer. [MIC 11]

Les composants COM ont habituellement quelques données associées, mais à la différence des objets C++, un composant COM donné n’aura jamais l’accès direct à un autre composant COM en sa totalité. Au lieu de cela, les composants COM accèdent toujours à d’autres composants COM par des pointeurs d’interface.

C’est un dispositif architectural primaire de COM, parce qu’il permet à COM de préserver complètement l’encapsulation des données et du traitement, une condition fondamentale d’un véritable standard de composant logiciel. Également, Il tient compte d’accès distant transparent (appelle inter-processus ou appel inter-réseau) parce que tout l’accès aux données est par les méthodes qui peuvent être consultées par une paire de proxy-stub qui expédient la demande du composant client au composant serveur et envoie également en arrière la réponse [MIC 11].

2.4.3 Les Types de Composant

On distingue trois types de composants classés en deux catégories, les composants “in-process” et les composants “out-of process”.

2.4.3.1 Les composants “in-process”

Les composants ou serveurs “in-process” sont chargés dans le processus de l’application cliente et sont par, là même, implémentés sous la forme de composants “dll”, c’est-à-dire qu’ils se présentent comme une bibliothèque de code binaire. Leur avantage est la rapidité d’exécution des appels de méthodes puisque ceux-ci ne nécessitent aucun changement de contexte de la part du système d’exploitation [MAR 98].

Par contre, ces composants ne peuvent être utilisés que dans le contexte d’un programme appelant, il ne peuvent pas être utilisés en tant qu’application autonome.

2.4.3.2 Les composants “out-of process”

Les composants ou serveurs “out-of process” sont exécutés dans des processus indépendants du processus de l’application cliente; ce sont donc des composants exécutables, aussi appelés composants séparés. On distingue deux types de composants “out-of process” [MAR 98]:

a. Les composants locaux

Le serveur s’exécute dans un processus séparé du client mais sur la même machine que celui ci. C’est un composant exécutable, donc également utilisable indépendamment d’un processus client. Microsoft Internet Explorer est un exemple de ces composants. Ces composants sont plus lents à l’exécution du fait du “basculement” entre processus.

b. Les composants distants

Le serveur s’exécute sur une machine distincte de celle du client et par conséquent dans un processus distinct ; ils font appel aux fonctionnalités de DCOM.

2.4.4 Les Interfaces

Dans COM, les applications agissent l’une sur l’autre et avec le système par des collections de fonctions appelées les interfaces. Notons que tous les services OLE sont simplement des interfaces COM.

COM “interface” est un contrat entre les composants logiciel pour fournir un ensemble petit mais utile d’opérations sémantiquement reliées (méthodes). Une interface est la définition d’un comportement prévu et s’est attendue à des responsabilités [MIC 11].

Les noms d’interface commencent par “I” par convention. OLE fournit un certain nombre d’interfaces d’usage universel utiles (qui commencent généralement par “IOle “), mais parce que n’importe qui peut définir les interfaces aussi bien, les développeurs peuvent développer leurs propres interfaces pendant qu’ils déploient des applications basées composant.

Par ailleurs, un pointeur à un composant COM est vraiment un pointeur à une des interfaces que le composant COM implémente; ceci signifie qu‟on peut seulement utiliser un pointeur de composant COM pour appeler une méthode, et pour ne pas modifier des données, comme décrit ci-dessus. Voici un exemple d’une interface, ILookup implémenté en langage C, avec deux méthodes membres [MIC 11] :

interface ILookup : public IUnknown

{
public:
virtual HRESULT _stdcall LookupByName ( LPTSTR lpName, TCHAR **lplpNumber) = 0;
virtual HRESULT _stdcall LookupByNumber( LPTSTR lpNumber, TCHAR **lplpName) = 0;
};

2.4.4.1 Les Attributs des interfaces

Étant donné qu’une interface est une manière contractuelle pour qu’un composant COM expose ses services, il y a plusieurs points très importants à comprendre [MIC 11]:

 Une interface n’est pas une classe.

Bien qu’une instance d’une classe puisse être créée (instancié) pour former un composant COM, une interface ne peut pas être instanciée par elle-même parce qu’elle ne porte aucune implémentation. Un composant COM doit mettre en application cette interface et ce composant doit être instancié afin qu’une interface puisse exister.

 Une interface n’est pas un composant COM.

Une interface est juste un groupe relatif de fonctions et est le standard binaire par laquelle les clients et les composants COM communiquent. Le composant COM peut être mis en application en n’importe quel langage avec n’importe quelle représentation interne d’état, à condition qu’il puisse fournir des pointeurs aux fonctions membres d’interface.

 Les clients COM agissent l’un sur l’autre seulement avec des pointeurs aux interfaces.

Quand un client COM a accès à un composant COM, il n’a rien davantage qu’un pointeur par lequel il peut accéder aux fonctions dans l’interface, appelé simplement un pointeur d’interface. Le pointeur serait opaque parce qu’il cache tous les aspects d’implémentation interne.

On ne peut pas voir les données du composant COM, par opposition aux pointeurs d’objet C++ par lesquels un client peut directement accéder aux données de l’objet. Dans COM, le client peut seulement appeler les méthodes d’interface à laquelle il a un pointeur. Cette encapsulation est ce qui permet à COM de fournir le standard binaire efficace, sûre, et robuste qui permet la transparence locale ou à distance.

 Les composants COM peuvent mettre en application des multiples interfaces.

Un composant COM peut mettre en application plus d’une interface. C’est-à-dire, les classes COM ont plus d’un ensemble de services à fournir. Par exemple, les classes COM pourrait

supporter la capacité d’échanger des données avec des clients COM, comme la capacité de sauvegarder son information persistante d’état dans un fichier à la demande du client. Chacune de ces capacités est exprimée par une interface différente (IDataObject et IPersistFile), ainsi le composant COM doit mettre en application deux interfaces.

 Les interfaces sont fortement identifiées. Chaque interface a son propre identificateur d’interface (un GUID), éliminant de ce fait n’importe quelle chance de collision qui se produirait avec des noms lisibles pour l’humain.

La différence entre les composants et les interfaces a deux implications importantes.

Quand on crée une nouvelle interface, on doit également créer un nouvel identificateur pour cette interface. Quand on utilise une interface, on doit utiliser l’identificateur de l’interface pour demander un pointeur à l’interface. Cette identification explicite améliore la robustesse en éliminant les conflits d’appellation qui auraient comme conséquence l’échec d’exécution.

 Les interfaces sont immuables.

Les interfaces COM ne sont pas jamais visionnées, ce qui signifie que des conflits de version entre les nouveaux et vieux composants sont évités. Une nouvelle version d’une interface, créée en ajoutant plus de fonctions ou en changeant la sémantique, est une interface entièrement nouvelle est assignée un nouvel, et unique identificateur.

Par conséquent une nouvelle interface n’est pas en conflit avec une vieille interface même si tout ce qui a changée est une opération ou la sémantique (mais ne pas égaliser la syntaxe) d’une méthode existante. Il est probable que deux interfaces très semblables puissent partager une implémentation interne commune.

Il est convenable d’adopter une représentation imagée standard pour des composants COM et leurs interfaces.


Figure 2.3 Une image typique d’un composant COM qui soutient trois interfaces: A, B, et C.


Figure 2.4 Les interfaces se prolongent vers les clients reliés à eux.


Figure 2.5 Deux applications peuvent relier entre eux des objets, dans ce cas, elles prolongent leurs interfaces l’une vers l’autre.

L’utilisation unique des interfaces dans COM fournit cinq avantages principaux [MIC 11] :

– La capacité de fonctionner dans les applications (clients ou serveurs des composants COM) Qui évoluent avec le temps.
– Interaction d’objet rapide et simple.
– Réutilisation d’interface.
– Transparence De Local/Remote.
– L’indépendance de langage de programmation.

2.4.5 IUnknown

COM définit une interface spéciale, IUnknown, pour mettre en application une certaine fonctionnalité essentielle. Tous les composants COM sont exigés pour mettre en application l’interface IUnknown et, commodément, toutes autres interfaces COM et OLE sont dérivées d’IUnknown. IUnknown a trois méthodes : QueryInterface, AddRef, et Release. En langage C++, IUnknown ressemble à ceci [MIC 11]:

interface IUnknown
{
virtual HRESULT QueryInterface(IID& iid, void** ppvObj) = 0;
virtual ULONG AddRef() = 0;
virtual ULONG Release() = 0;
}

La figure 2.5 est une représentation graphique d’IUnknown.


Figure 2.5 L’interface IUnknown

AddRef et Release sont une référence simple comptant des méthodes. La méthode AddRef() d’un composant COM s’appelle quand un autre composant COM utilise l’interface; la méthode Release du composant COM s’appelle quand l’autre composant ne demande plus l’utilisation de cette interface. Tandis que le compte de la référence du composant COM est différent de zéro, il doit demeurer dans la mémoire; quand le compte de référence devient zéro, le composant COM peut sans risque se décharger, parce que aucun autre composant tient des références à lui [MIC 11].

QueryInterface est le mécanisme qui permet à des clients de découvrir dynamiquement (au temps d’exécution) si une interface est soutenue par un composant COM; en même temps, c’est le mécanisme que le client utilise pour obtenir un pointeur à une interface d’un composant COM. Quand une application veut utiliser une certaine fonction d’un composant COM, elle appelle QueryInterface de cet objet, demandant un pointeur à l’interface qui met en application la fonction désirée.

Si le composant COM supporte cette interface, il renverra le pointeur approprié d’interface et un code de succès. Si le composant COM ne soutient pas l’interface demandée, il renverra une valeur d’erreur. L’application examinera alors le code retourné; si réussie, elle utilisera le pointeur d’interface pour accéder à la méthode désirée. Si le QueryInterface échouait, l’application prendra une autre action, faisant l’utilisateur savoir que la méthode désirée n’est pas disponible [MIC 11].

2.4.5.1 Le Langage IDL

L‟interface COM doit être indépendante du langage de programmation, c à d, elle doit pouvoir être définie dans n‟importe quel autre langage. L‟exemple suivant montre l‟implémentation en langage java et C++ d‟une interface « Iperso » possédant une seule méthode:

Interface Iperso codée en Java :

public interface Iperso extends com.ms.com.IUnknown
{ public abstract int fonctionPerso(int x , int y) ; }

Interface Iperso codée en C++ :

class Iperso : public IUnknown
{ virtual HRESULT _stdcall fonctionPerso(int x , int y , int* retval) = 0;
}

Ces deux interfaces sont correctes mais non indépendantes du langage. La solution est obtenue par l‟utilisation du langage IDL (Interface Definition Language) qui est un langage servant à définir des interfaces. La Définition d‟une interface en IDL se fait suivant la syntaxe suivante:

[//Interface header
uuid(…), helpstring(“…”), version(1.0), …
]
interface IEmployee : IDispatch // ou IUnknown
{//Interface body
HRESULT Promote([in] long argin, [out] long* argout);
}

Les qualificateurs entre [ ] spécifient la nature de chaque argument :

 [in] : valeur lue en entrée de la méthode

 [out] : valeur pouvant être modifiée par la méthode

L‟exemple suivant donne la définition de l‟interface Iperso en langage IDL :

import “unknown.idl”;//Contient la définition de l’interface IUnknown
// object = mot clé identifiant une interface COM [
object, uuid(10000001-0000-0000-0000-000000000001)]
interface Iperso : IUknown

{
HRESULT FonctionPerso([in]int x,[in]int y, [out,retval]int* retval);
};

Page suivante : 2.5 Bibliothèque COM (COM Library)

Retour au menu : UTILISATION DES SCRIPTS POUR LE DEVELOPPEMENT DES COMPOSANTS COM ADAPTABLES