Utilisation d’une liaison anticipée et d’une liaison tardive dans Automation
Résumé
La façon dont vous liez un serveur Automation peut affecter de nombreuses choses dans votre programme, telles que les performances, la flexibilité et la facilité de maintenance.
Cet article explique les types de liaison disponibles pour les clients Automation et pèse les deux côtés de chaque méthode.
Informations supplémentaires
L’automatisation est un processus dans lequel un composant logiciel communique avec et/ou contrôle un autre composant logiciel à l’aide du modèle COM (Component Object Model) de Microsoft. Il constitue la base de la plupart des communications entre composants utilisées dans des langages tels que Visual Basic ou Visual Basic pour Applications, et il est devenu une partie normale de la plupart des programmes.
Historiquement, un objet Automation est tout objet qui prend en charge l’interface IDispatch. Cette interface permet aux clients d’appeler des méthodes et des propriétés au moment de l’exécution sans avoir à connaître l’objet exact avec lequel ils communiquent au moment du design ; processus appelé liaison tardive. Aujourd’hui, toutefois, le terme Objet Automation peut être appliqué à pratiquement n’importe quel objet COM, même ceux qui ne prennent pas en charge IDispatch (et ne peuvent donc pas être liés en retard). Cet article suppose que l’objet que vous automatiser prend en charge les deux méthodes de liaison.
Qu’est-ce que la liaison ?
La liaison est un processus de correspondance des appels de fonction écrits par le programmeur au code réel (interne ou externe) qui implémente la fonction. Elle est effectuée lorsque l’application est compilée, et toutes les fonctions appelées dans le code doivent être liées avant que le code puisse être exécuté.
Pour comprendre le processus, pensez à « lier » en termes de publication d’un livre. Imaginez que votre code ressemble au texte du livre où, dans un certain paragraphe, vous avez écrit quelque chose comme « voir le chapitre 12, page x pour plus de détails ». Vous ne savez pas quel est le numéro de page tant que le livre n’est pas terminé. Par conséquent, avant que le paragraphe puisse être lu comme prévu, toutes les pages du livre doivent être liées et le numéro de page approprié doit être inséré dans le paragraphe. Vous attendez que le livre soit « lié » avant de pouvoir référencer d’autres parties du livre.
Le logiciel de liaison est similaire. Votre code est constitué de parties qui doivent être regroupées avant que le code puisse être « lu ». La liaison est l’action de remplacer les noms de fonction par des adresses mémoire (ou des décalages de mémoire, pour être plus précis) où le code « passe à » quand la fonction est appelée. Pour les objets COM, l’adresse est un décalage de mémoire dans une table de pointeurs (appelée table v) détenue par l’objet. Lorsqu’une fonction COM est liée, elle est liée via la table v.
La structure d’un objet COM est simple. Lorsque votre code contient une référence à un objet, il contient un pointeur indirect vers le haut de la table v. La table v est un tableau d’adresses mémoire où chaque entrée est une fonction différente qui peut être appelée sur cet objet. Pour appeler la troisième fonction sur un objet COM, vous descendez trois entrées dans la table, puis vous accédez à l’emplacement de mémoire indiqué ici. Cela exécute le code de la fonction et, une fois terminé, vous retourne prêt à exécuter la ligne de code suivante.
+-[Code]------------+ +.................................[COM Object]...+
| | : +-------------+ :
|Set obj = Nothing -|--->| obj pointer | :
| | : +-|-----------+ :
+-------------------+ : | +-----------------+ :
: +-->| v-table pointer | :
: +--|--------------+ :
: | :
: | +----------------------------+ :
: (3rd) | | Function 1 Address pointer | :
: (Offset) | +----------------------------+ :
: | | Function 2 Address pointer | :
: | +----------------------------+ :
: +->| Function 3 Address pointer | :
: +----------------------------+ :
+................................................+
L’exemple ci-dessus montre ce qui se passe lors de la libération d’un objet COM. Étant donné que tous les objets COM héritent d’IUnknown, les trois premières entrées de la table sont les méthodes d’IUnknown. Lorsque vous devez libérer un objet, votre code appelle la troisième fonction de la table v (IUnknown::Release).
Heureusement, ce travail est effectué par Visual Basic en arrière-plan. En tant que programmeur Visual Basic, vous n’avez jamais à vous occuper directement d’une table virtuelle. Mais, cette structure est la façon dont tous les objets COM sont liés, et il est important que vous êtes familiarisé avec elle pour comprendre ce qu’est la liaison.
Liaison anticipée
L’exemple ci-dessus est ce que l’on appelle une liaison précoce (ou table v). Pour tous les objets COM, cette forme de liaison a lieu chaque fois que l’interface IUnknown d’un objet COM est appelée. Mais qu’en est-il des autres fonctions de l’objet ? Comment appeler sa méthode Refresh ou sa propriété Parent ? Il s’agit de fonctions personnalisées qui sont généralement uniques à un objet. Si leurs emplacements dans la table v ne peuvent pas être supposés, comment trouvez-vous les adresses de fonction nécessaires pour les appeler ?
La réponse, bien sûr, dépend de savoir si vous savez à l’avance à quoi ressemble la table v de l’objet. Si vous le faites, vous pouvez effectuer le même processus de liaison précoce aux méthodes personnalisées de l’objet que vous l’avez fait pour ses méthodes IUnknown. C’est ce que l’on entend généralement par « liaison anticipée ».
Pour utiliser la liaison anticipée sur un objet, vous devez savoir à quoi ressemble sa table v. Dans Visual Basic, vous pouvez le faire en ajoutant une référence à une bibliothèque de types qui décrit l’objet, son interface (table v) et toutes les fonctions qui peuvent être appelées sur l’objet. Une fois cette opération effectuée, vous pouvez déclarer un objet comme étant un certain type, puis définir et utiliser cet objet à l’aide de la table v. Par exemple, si vous souhaitez automatiser Microsoft Office Excel à l’aide d’une liaison anticipée, vous devez ajouter une référence à la bibliothèque d’objets Microsoft Excel 8.0 à partir du projet| Boîte de dialogue Références, puis déclarez votre variable comme étant de type « Excel.Application ». À partir de là, tous les appels effectués à votre variable d’objet seront liés tôt :
' Set reference to 'Microsoft Excel 8.0 Object Library' in
' the Project|References dialog (or Tools|References for VB4 or VBA).
' Declare the object as an early-bound object
Dim oExcel As Excel.Application
Set oExcel = CreateObject("Excel.Application")
' The Visible property is called via the v-table
oExcel.Visible = True
Cette méthode fonctionne très bien la plupart du temps, mais que se passe-t-il si vous ne connaissez pas l’objet exact que vous utiliserez au moment du design ? Par exemple, que se passe-t-il si vous avez besoin de parler à plusieurs versions d’Excel, ou éventuellement à un objet « inconnu » ?
Liaison tardive
COM inclut IDispatch. Les objets qui implémentent IDispatch ont une dispinterface (s’il s’agit de la seule interface qu’ils prennent en charge) ou une interface double (s’ils ont également une interface personnalisée à laquelle vous pouvez établir une liaison anticipée). Les clients qui se lient à IDispatch sont dits « liés tardivement », car la propriété ou la méthode exacte qu’ils appellent sont déterminées au moment de l’exécution à l’aide des méthodes d’IDispatch pour les localiser. Pour revenir à l’exemple de livre précédent, considérez-le comme une note de bas de page qui vous dirige vers la table des matières où vous devez « rechercher » le numéro de page au « moment de lecture » plutôt que de le faire déjà imprimer dans le texte.
La magie de l’interface est contrôlée par deux fonctions : GetIDsOfNames et Invoke. La première mappe les noms de fonction (chaînes) à un identificateur (appelé dispid) qui représente la fonction. Une fois que vous connaissez l’ID de la fonction que vous souhaitez appeler, vous pouvez l’appeler à l’aide de la fonction Invoke. Cette forme d’appel de méthode est appelée « liaison tardive ».
Là encore, en Visual Basic, vous spécifiez comment l’objet est lié par votre déclaration d’objet. Si vous déclarez une variable d’objet en tant qu'« Objet », vous indiquez en fait à Visual Basic d’utiliser IDispatch et, par conséquent, la liaison est tardive :
' No reference to a type library is needed to use late binding.
' As long as the object supports IDispatch, the method can
' be dynamically located and invoked at run-time.
' Declare the object as a late-bound object
Dim oExcel As Object
Set oExcel = CreateObject("Excel.Application")
' The Visible property is called via IDispatch
oExcel.Visible = True
Comme vous pouvez le voir, le reste de votre code est le même. La seule différence entre la liaison anticipée et la liaison tardive (en termes de code que vous écrivez) réside dans la déclaration de variable.
Il est important de noter que ce qui est « limite tardive » est la fonction appelée et non la façon dont elle est appelée. Dans la discussion précédente sur la liaison en général, vous devez remarquer que IDispatch lui-même est « limite anticipée : » c’est-à-dire que Visual Basic effectue l’appel pour définir la propriété Visible via une entrée de table v (IDispatch::Invoke) comme pour tout appel COM. L’objet COM lui-même est chargé de transférer l’appel à la fonction appropriée pour rendre Excel visible. Cette indirection permet de compiler le client Visual Basic (c’est-à-dire lié à une adresse de fonction valide), mais ne connaît toujours pas la fonction exacte qui effectuera réellement le travail.
Liaison dispidée
Certains clients Automation (plus notablement MFC et Visual Basic 3.0, mais aussi Visual Basic 5.0 et 6.0 en ce qui concerne les contrôles ActiveX) utilisent une forme hybride de liaison tardive appelée liaison dispid. Si l’objet COM est connu au moment du design, les dispids des fonctions appelées peuvent être mis en cache et transmis directement à IDispatch::Invoke sans avoir à appeler GetIDsOfNames au moment de l’exécution. Cela peut considérablement augmenter les performances, car au lieu d’effectuer deux appels COM par fonction, vous n’avez besoin d’en effectuer qu’un.
La liaison dispid n’est pas une option que vous pouvez normalement choisir dans Visual Basic 5.0 ou 6.0. Il est utilisé pour les objets référencés dans une bibliothèque de types, mais qui ne contiennent pas d’interface personnalisée (c’est-à-dire pour les objets qui ont un dispinterface uniquement) et pour les contrôles ActiveX agrégés, mais, en général, Visual Basic utilise la liaison anticipée à n’importe quel endroit où vous utiliseriez normalement une liaison déconseillée.
Quelle forme de liaison dois-je utiliser ?
La réponse à cette question dépend autant de la conception de votre projet que de tout autre élément. Microsoft recommande une liaison anticipée dans presque tous les cas. Toutefois, il peut y avoir des raisons de choisir la liaison tardive.
La liaison anticipée est la méthode préférée. Il s’agit du meilleur performeur, car votre application se lie directement à l’adresse de la fonction appelée et il n’y a pas de surcharge supplémentaire dans l’exécution d’une recherche. En termes de vitesse d’exécution globale, elle est au moins deux fois plus rapide que la liaison tardive.
La liaison anticipée assure également la sécurité des types. Lorsque vous avez défini une référence à la bibliothèque de types du composant, Visual Basic fournit la prise en charge d’IntelliSense pour vous aider à coder chaque fonction correctement. Visual Basic vous avertit également si le type de données d’un paramètre ou d’une valeur de retour est incorrect, ce qui vous permet d’économiser beaucoup de temps lors de l’écriture et du débogage du code.
La liaison tardive est toujours utile dans les situations où l’interface exacte d’un objet n’est pas connue au moment du design. Si votre application cherche à communiquer avec plusieurs serveurs inconnus ou doit appeler des fonctions par nom (à l’aide de la fonction CallByName Visual Basic 6.0 par exemple), vous devez utiliser la liaison tardive. La liaison tardive est également utile pour contourner les problèmes de compatibilité entre plusieurs versions d’un composant qui a modifié ou adapté de manière incorrecte son interface entre les versions.
Les avantages offerts à la liaison anticipée en font le meilleur choix dans la mesure du possible.
Maintien de la compatibilité entre plusieurs versions
Si vous utilisez un composant que vous ne redistribuez pas avec votre package d’installation et que vous ne pouvez pas être assuré de la version exacte avec laquelle vous communiquerez au moment de l’exécution, vous devez prêter une attention particulière à la liaison anticipée à une interface compatible avec toutes les versions du composant, ou (dans certains cas) utiliser la liaison tardive pour appeler une méthode qui peut exister dans une version particulière et échouer correctement si cette méthode n’est pas présent dans la version installée sur le système client.
Les applications Microsoft Office fournissent un bon exemple de ces serveurs COM. Les applications Office développent généralement leurs interfaces pour ajouter de nouvelles fonctionnalités ou corriger les lacunes précédentes entre les versions. Si vous devez automatiser une application Office, il est recommandé de lier au plus tôt la version la plus ancienne du produit qui, selon vous, pourrait être installée sur le système de votre client. Par exemple, si vous devez être en mesure d’automatiser Excel 95, Excel 97, Excel 2000 et Excel 2002, vous devez utiliser la bibliothèque de types pour Excel 95 (XL5en32.olb) pour maintenir la compatibilité avec les trois versions.
Les applications Office montrent également que les modèles objet avec de grandes interfaces doubles peuvent subir des limitations dans le marshaling sur certaines plateformes. Pour que votre code fonctionne mieux sur toutes les plateformes, utilisez IDispatch.
References
Pour plus d’informations sur COM, les tables v et l’utilisation d’Automation, consultez les livres suivants :
Rogerson, Dale, Inside COM, MSPRESS, ISBN: 1-57231-349-8.
Curland, Matt, Advanced Visual Basic 6, DevelopMentor, 0201707128.