Appel d’un composant .NET à partir d’un composant COM

 

Mike Gunderloy
Lark Group, Inc.

Janvier 2002

Résumé: Décrit en détail comment appeler des serveurs Microsoft .NET à partir de clients COM. (12 pages imprimées)

Objectifs

  • Comprendre le concept des wrappers com callables
  • Créer un serveur .NET qui peut être appelé à partir de Microsoft® Visual Basic® 6.0
  • Utiliser les utilitaires sn, regasm et gacutil
  • Écrire du code Visual Basic 6.0 qui utilise une classe .NET

Hypothèses

Les éléments suivants doivent être vrais pour vous permettre de tirer le meilleur parti de ce document :

  • Vous êtes familiarisé avec la programmation Visual Basic
  • Vous êtes familiarisé avec les concepts COM
  • Vous avez accès à Visual Basic .NET
  • Vous comprenez l’architecture .NET globale
  • Vous comprenez comment créer des classes publiques dans Visual Basic .NET

Contenu

La joie de l’interopérabilité
Création de classes .NET à utiliser dans des applications COM
Pratiquez l’appel d’un composant .NET à partir de COM
Nouveautés de Visual Basic 6.0
Résumé

La joie de l’interopérabilité

Parfois, une révolution dans la programmation vous oblige à abandonner tout ce qui est arrivé avant. Pour prendre un exemple extrême, supposons que vous écriviez des applications Visual Basic depuis des années. Si vous êtes comme de nombreux développeurs, vous aurez créé un inventaire substantiel de code au cours de cette période. Et si vous avez suivi les recommandations de différents gourous du langage, ce code est en composant. Autrement dit, en utilisant des serveurs COM (Component Object Model) (anciennement Microsoft® ActiveX®), vous avez divisé votre application en blocs de fonctionnalités pouvant être appelées. Bien sûr, vous êtes également susceptible d’avoir un investissement important dans des composants, tels que les contrôles ActiveX, d’autres développeurs et d’autres entreprises.

Mais que se passe-t-il si vous décidez du changement radical de développement vers un autre système d’exploitation entièrement ? À ce stade, tout votre investissement dans COM devient inutile. Vous ne pouvez pas utiliser votre code existant et vous devez apprendre à tout faire sur la nouvelle plateforme. Ce serait sans aucun doute un coup dur pour votre productivité.

Heureusement, le passage de COM à .NET n’implique aucune perte radicale de productivité. Il existe deux concepts clés qui facilitent considérablement le passage du développement COM au développement .NET, sans perte de base de code ou de productivité :

  • Les composants .NET peuvent appeler des composants COM.
  • Les composants COM peuvent appeler des composants .NET.

Cette interopérabilité bidirectionnel est la clé pour passer de COM à .NET. À mesure que vous apprenez les subtilités de .NET, vous pouvez continuer à utiliser les composants COM. Il existe un certain nombre de situations où cette interopérabilité est utile :

  • Le basculement vers .NET ne sera pas instantané. L’apprentissage des concepts et de l’implémentation de la programmation .NET prend du temps. Vous constaterez donc probablement que vous devez continuer à travailler avec du code COM pendant que vous, vos collègues et vos fournisseurs êtes à la hauteur.
  • Le code que vous pouvez migrer vers .NET ne peut pas être migré en une seule fois. Vous souhaiterez migrer, puis tester chaque composant migré individuellement.
  • Vous utilisez peut-être des composants COM tiers que vous ne pouvez pas convertir en .NET et où le fournisseur n’a pas encore publié de version .NET.
  • Bien que le code Visual Basic 6.0 migre vers .NET, la migration n’est pas parfaite. Vous pouvez avoir des composants qui ne peuvent pas être déplacés vers .NET en raison d’une implémentation ou d’un langage bizarre.

Dans ce document, vous allez découvrir les détails de l’appel de serveurs .NET à partir de clients COM. Dans un autre document de cette série, Appel de composants COM à partir de clients .NET, vous allez découvrir comment appeler dans l’autre sens, des clients .NET aux serveurs COM.

Création de classes .NET à utiliser dans des applications COM

Bien que les clients COM puissent appeler du code exposé dans une classe publique par les serveurs .NET, le code .NET n’est pas directement accessible aux clients COM. Pour utiliser du code .NET à partir d’un client COM, vous devez créer un proxy appelé wrapper COM (CCW). Dans cette section, vous allez découvrir l’architecture CCW, ainsi que les étapes nécessaires pour créer et déployer une classe .NET à utiliser par les clients COM.

Wrappers CCW (COM Callable Wrapper)

Le code qui fonctionne dans le Common Language Runtime (CLR) .NET est appelé code managé. Ce code a accès à tous les services que le CLR apporte à la table, tels que l’intégration multilingue, la sécurité et la prise en charge du contrôle de version et le garbage collection. Le code qui ne fonctionne pas dans le CLR est appelé code non managé. Étant donné que COM a été conçu avant l’existence du CLR et que le code COM ne fonctionne pas dans l’infrastructure fournie par le CLR, il ne peut pas utiliser les services CLR. Tous vos composants COM sont, par définition, du code non managé.

Les composants de code managé dépendent non seulement du CLR, mais ils nécessitent également que les composants avec lesquels ils interagissent dépendent du CLR. Étant donné que les composants COM ne fonctionnent pas dans le CLR, ils ne peuvent pas appeler directement des composants de code managé. Le code non managé ne peut tout simplement pas accéder au CLR pour appeler directement des composants managés.

Le moyen de sortir de ce dilemme est d’utiliser un proxy. En termes généraux, un proxy est un logiciel qui accepte les commandes d’un composant, les modifie et les transfère à un autre composant. Le type particulier de proxy utilisé pour appeler du code managé à partir de code non managé est appelé wrapper COM, ou CCW. La figure 1 montre schématiquement comment les ccw chevauchent la limite entre le code managé et le code non managé. Cette figure inclut un programme COM nommé ComUI.exe, deux composants .NET nommés NETService.dll et Utility.dll, ainsi que la technologie nécessaire qui les connecte.

Figure 1. Appel de code managé avec des CCW

Conditions préalables pour les classes pouvant être appelées COM

Il existe deux conditions préalables à garder à l’esprit lors de la création d’une classe .NET qui sera utilisée par les clients COM.

Tout d’abord, définissez explicitement une interface dans votre code Visual Basic .NET et la classe implémentez l’interface. Par exemple, cet extrait de code définit une interface nommée iFile et une classe qui implémente l’interface :

Public Interface iFile
    Property Length() As Integer
End Interface

Public Class TextFile
    Implements iFile
    ' details omitted
End Class

L’implémentation de fonctionnalités via des interfaces présente un avantage majeur pour les clients COM. .NET maintient la cohérence des interfaces avec les versions précédentes lors de la génération de ccw. Cela permet d’empêcher les modifications apportées à votre serveur .NET d’interrompre les clients COM.

Deuxièmement, toute classe qui doit être visible par les clients COM doit être déclarée publique. Les outils qui créent le CCW définissent uniquement des types basés sur des classes publiques. La même règle s’applique aux méthodes, propriétés et événements qui seront utilisés par les clients COM.

Vous devez également envisager de signer des assemblys .NET contenant des classes qui seront utilisées par COM avec une paire de clés de chiffrement. Microsoft appelle cela la signature de l’assembly avec un nom fort. La signature d’un assembly avec un nom fort permet à .NET de s’assurer que le code de l’assembly n’a pas été modifié depuis la publication de l’assembly. Il s’agit d’une exigence pour tous les assemblys globaux, qui sont des assemblys qui doivent être partagés par plusieurs clients, bien que les assemblys non signés puissent également être appelés par les clients COM.

Note Il est possible d’utiliser un assembly non signé à partir d’un client COM en déployant l’assembly directement dans le répertoire du client COM en tant qu’assembly privé. Ce document ne couvre pas l’approche d’assembly privé, car les assemblys globaux sont plus compatibles que les assemblys privés avec l’architecture de la plupart des applications COM.

Il est recommandé de signer tous les assemblys, même les assemblys privés. Cela permet de générer de meilleurs CLSID pour les classes managées et d’éviter les collisions entre les classes dans différents assemblys.

Pour créer un nom fort, vous pouvez utiliser l’outil sn. Il existe de nombreuses options pour cet outil en ligne de commande, et vous pouvez taper sn /? à une invite de commandes pour les afficher toutes. L’option dont vous avez besoin pour signer un assembly est -k, ce qui crée un fichier de clé. Par défaut, les fichiers de clés utilisent l’extension .snk. Par exemple, pour créer un fichier de clé nommé NETServer.snk, vous pouvez utiliser cette ligne de commande :

sn -k NETServer.snk

Déployer une application pour accéder à COM

Une fois que vous avez créé un assembly .NET contenant une classe qui sera appelée par un client COM, il existe trois étapes pour rendre la classe disponible pour COM.

Tout d’abord, vous devez créer une bibliothèque de types pour l’assembly. Une bibliothèque de types est l’équivalent COM des métadonnées contenues dans un assembly .NET. Les bibliothèques de types sont généralement contenues dans des fichiers avec l’extension .tlb. Une bibliothèque de types contient les informations nécessaires pour permettre à un client COM de déterminer quelles classes se trouvent dans un serveur particulier, ainsi que les méthodes, les propriétés et les événements pris en charge par ces classes. Le Kit de développement logiciel (SDK) .NET Framework inclut un outil nommé tlbexp (exportateur de bibliothèque de types) qui peut créer une bibliothèque de types à partir d’un assembly. Tlbexp inclut un certain nombre d’options, et vous pouvez taper tlbexp /? à l’invite de commandes pour les afficher toutes. L’une de ces options est l’option /out, qui vous permet de spécifier le nom de la bibliothèque de types générée. (Un est créé pour vous si vous ne choisissez pas de créer votre propre nom.) Par exemple, pour extraire les métadonnées d’un assembly nommé NETServer.dll vers une bibliothèque de types nommée NETServer.tlb, vous pouvez utiliser cette ligne de commande :

tlbexp NETServer.dll /out:NETServer.tlb

Deuxièmement, vous devez utiliser l’outil d’inscription d’assembly (regasm) à partir du Kit de développement logiciel (SDK) .NET Framework pour créer la bibliothèque de types et l’inscrire en une seule opération. Il s’agit de l’outil le plus simple à utiliser lorsque vous effectuez à la fois le développement .NET et COM sur un seul ordinateur. Comme tlbexp, il existe un certain nombre d’options pour le regasm; Tapez regasm /? à l’invite de commandes pour les afficher tous. Pour créer et inscrire une bibliothèque de types à l’aide de regasm, utilisez une ligne de commande telle que :

regasm /tlb:NETServer.tlb NETServer.dll

Troisièmement, vous devez installer l’assembly .NET dans global Assembly Cache (GAC) afin qu’il soit disponible en tant qu’assembly partagé. Pour installer un assembly dans le GAC, utilisez l’outil gacutil :

gacutil /i NETServer.dll

Là encore, vous pouvez obtenir la liste de toutes les options de gacutil en tapant gacutil /? à une invite de commandes.

S’entraîner à appeler un composant .NET à partir de COM

Dans l’exemple suivant, vous allez utiliser des propriétés et des méthodes dans un composant .NET à partir du code COM. Vous allez utiliser regasm pour créer une bibliothèque de types à partir de l’assembly .NET et inscrire un assembly, et vous allez utiliser gacutil pour rendre l’assembly disponible dans le monde entier. Vous verrez ensuite comment utiliser cet assembly .NET à partir du code COM Visual Basic 6.0.

Créer l’assembly .NET

Pour créer l’assembly .NET contenant une classe publique, procédez comme suit :

  1. Ouvrez Microsoft® Visual Studio® .NET, puis cliquez sur Nouveau projet dans la page d’accueil.

  2. Sélectionnez Projet Visual Basic dans l’arborescence située à gauche de l’écran.

  3. Sélectionnez Bibliothèque de classes comme modèle de projet.

  4. Définissez le nom de l’application sur PhysServer2 , puis cliquez sur OK pour créer le projet.

  5. Mettez en surbrillance la classe appelée Class1.vb dans la fenêtre Explorateur de solutions et renommez-la en NETTemperature.vb.

  6. Sélectionnez le code pour Class1 dans NETTemperature.vb (il s’agit d’une définition de classe vide) et remplacez-le par le code suivant :

    Public Interface iTemperature
        Property Celsius() As Double
        Property Fahrenheit() As Double
        Function GetCelsius() As Double
        Function GetFahrenheit() As Double
    End Interface
    
    Public Class NET_Temperature
        Implements iTemperature
    
        Private mdblCelsius As Double
        Private mdblFahrenheit As Double
    
        Public Property Celsius() As Double _
         Implements iTemperature.Celsius
            Get
                Celsius = mdblCelsius
            End Get
            Set(ByVal Value As Double)
                mdblCelsius = Value
                mdblFahrenheit = ((Value * 9) / 5) + 32
            End Set
        End Property
    
        Public Property Fahrenheit() As Double _
         Implements iTemperature.Fahrenheit
            Get
                Fahrenheit = mdblFahrenheit
            End Get
            Set(ByVal Value As Double)
                mdblFahrenheit = Value
                mdblCelsius = ((Value - 32) * 5) / 9
            End Set
        End Property
    
        Public Function GetCelsius() As Double _
         Implements iTemperature.GetCelsius
            GetCelsius = mdblCelsius
        End Function
    
        Public Function GetFahrenheit() As Double _
         Implements iTemperature.GetFahrenheit
            GetFahrenheit = mdblFahrenheit
        End Function
    End Class
    

Ce code commence par définir une interface nommée iTemperature. Étant donné que l’interface est définie avec le mot clé public, elle sera exportée vers la bibliothèque de types que vous allez créer à partir de cet assembly. Vous pouvez considérer une définition d’interface comme le squelette de la totalité ou d’une partie d’une définition de classe. La définition d’interface peut contenir des membres (propriétés, méthodes( fonctions ou sous-éléments) et des événements, tout comme une classe. Mais contrairement à une classe, une définition d’interface ne contient aucun code pour l’un de ces membres. Une classe peut implémenter une interface (comme dans cet exemple) ou plusieurs interfaces.

Ce code définit la classe NET_Temperature qui utilise l’interface iTemperature. En particulier, cette ligne de la définition de classe configure un contrat entre la classe et l’interface :

Implements iTemperature

Le contrat indique que la classe implémentera tous les membres de l’interface. Il peut également contenir des membres supplémentaires qui ne font pas partie de l’interface, mais vous obtiendrez une erreur si vous essayez de créer une classe qui n’implémente pas complètement une interface.

Note La classe expose deux propriétés publiques et deux méthodes publiques. (Pour connaître les principes de base de la création de classes, de méthodes et de propriétés, consultez Création de classes dans Visual Basic .NET).

Notez la syntaxe utilisée pour associer les membres de la classe aux membres de l’interface que la classe implémente. Par exemple, la propriété Celsius dans la classe NET_Temperature est définie de cette façon :

Public Property Celsius() As Double _
 Implements iTemperature.Celsius

Cette ligne de code définit une propriété qui retourne un double et indique au compilateur que cette propriété est une implémentation de la propriété Celsius dans l’interface iTemperature .

Créer une paire de clés et signer l’assembly

Pour que l’assembly soit disponible dans le monde entier, vous devez créer une paire de clés et l’utiliser pour signer l’assembly. En outre, vous pouvez faciliter l’utilisation de l’assembly en ajoutant un titre et une description.

Pour signer l’assembly, vous pouvez exécuter l’utilitaire sn et ajouter manuellement le nom du fichier de clé, ou générer un nom fort à l’aide de l’interface utilisateur de Visual Studio .NET. Nous allons utiliser cette dernière méthode. Pour ce faire, procédez comme suit :

  1. Dans le Explorateur de solutions dans Visual Studio .NET, double-cliquez sur le fichier AssemblyInfo.vb pour l’ouvrir dans la fenêtre d’édition.

  2. Dans la section Attributs d’assembly en haut de ce fichier, modifiez les lignes AssemblyTitle et AssemblyDescription pour lire :

    <Assembly: AssemblyTitle("PhysServer2")> 
    <Assembly: AssemblyDescription(".NET Version of PhysServer")> 
    

    **Pointe!   **Les attributs d’assembly dans Visual Basic .NET sont l’équivalent des propriétés du projet dans Visual Basic 6.0.

  3. Dans le Explorateur de solutions, cliquez avec le bouton droit sur le nœud du projet, puis choisissez Propriétés. Cliquez sur le dossier Propriétés communes , puis sur la page de propriétés Nom fort . Sélectionnez la zone intitulée Générer un nom fort à l’aide. Cliquez sur Générer une clé pour générer un fichier de clé et l’ajouter à votre projet. Cliquez sur OK pour fermer la boîte de dialogue de propriété.

Vous êtes maintenant prêt à créer l’assembly. Cliquez sur Générer ou appuyez sur Ctrl+Maj+B pour générer l’assembly.

Inscrire l’assembly et créer une bibliothèque de types

À ce stade, vous pouvez utiliser le nouvel assembly et la classe NET_Temperature à partir d’une autre application .NET. Toutefois, vous devez toujours rendre la classe et ses membres disponibles pour vos applications COM. Ouvrez une invite de commandes Visual Studio .NET (cliquez sur Démarrer, puis Programmes, Puis Microsoft Visual Studio .NET 7.0, Visual Studio .NET Tools, puis Visual Studio .NET Command Prompt), accédez au répertoire du projet pour PhysServer2, puis tapez :

regasm /tlb:PhysServer2.tlb PhysServer2.dll

L’utilitaire regasm crée une bibliothèque de types et l’inscrit dans votre registre Windows pour rendre les classes dans PhysServer2.dll disponibles pour les clients COM.

Ajouter l’assembly au Global Assembly Cache

Enfin, pour que l’assembly nouvellement enregistré soit disponible dans le monde entier pour tous les clients COM où qu’ils se trouvent sur votre disque dur, revenez à l’invite de commandes Visual Studio .NET et tapez :

gacutil /I PhysServer2.dll

L’utilitaire gacutil ajoute l’assembly au GAC et imprime un message status pour vous indiquer que c’est fait.

Écrire du code Visual Basic 6.0 pour appeler la classe .NET

Vous êtes maintenant prêt à écrire un client COM pour utiliser la classe NET_Temperature . Procédez comme suit :

  1. Ouvrez Visual Basic 6.0 et dans la boîte de dialogue Nouveau projet, cliquez sur Nouvel onglet.

  2. Sélectionnez Standard EXE , puis cliquez sur Ouvrir.

  3. Mettez en surbrillance le formulaire appelé Form1 dans la fenêtre Project Explorer et renommez-le en frmTemperature.

  4. Créez le formulaire illustré dans la figure 2 en ajoutant les contrôles appropriés et en définissant les propriétés de ces contrôles, comme indiqué dans le tableau 1.

    Tableau 1. Contrôles pour frmTemperature

    Type de contrôle Propriété Valeur
    Étiquette Nom lblFahrenheit
      Caption Fahrenheit
    TextBox Nom txtFahrenheit
      Texte (vide)
    Bouton Nom cmdConvertToC
      Caption Convertir en C
    Étiquette Nom lblCelsius
      Caption Celsius
    TextBox Nom txtCelsius
      Texte (vide)
    Bouton Nom cmdConvertToF
      Caption Convertir en F

    Figure 2 : Conception du formulaire de test

  5. Pour utiliser la classe dans PhysServer2 via le CCW, cliquez sur Projet, puis sur Références pour ouvrir la boîte de dialogue Références. Sélectionnez la référence pour la version .NET de PhysServer, comme illustré dans la figure 3. Cliquez sur OK pour fermer la boîte de dialogue.

    Figure 3. Définition d’une référence au composant .NET

Vous êtes maintenant prêt à écrire du code qui utilise les méthodes et les propriétés de la classe NET_Temperature . Dans le menu Affichage , cliquez sur Code, puis entrez ce code dans le module de formulaire pour frmTemperature :

Private moTempClass As PhysServer2.NET_Temperature
Private moTemp As PhysServer2.iTemperature

Private Sub cmdConvertToC_Click()
    With moTemp
        .Fahrenheit = txtFahrenheit.Text
         txtCelsius.Text = .GetCelsius
    End With
End Sub

Private Sub cmdConvertToF_Click()
    With moTemp
        .Celsius = txtCelsius.Text
        txtFahrenheit.Text = .GetFahrenheit
    End With
End Sub

Private Sub Form_Load()
    Set moTempClass = New PhysServer2.NET_Temperature
    Set moTemp = moTempClass
End Sub

N’oubliez pas que dans le projet .NET, vous avez défini la classe Net_Temperature à l’aide de l’interface iTemperature . Ce code montre comment récupérer l’interface (représentée sous la forme d’un objet nommé moTemp) à partir de l’objet . Bien que cela puisse ressembler à du code supplémentaire, si vous expérimentez en Visual Basic, vous constaterez qu’il est beaucoup plus pratique d’utiliser l’interface qu’avec l’objet . En effet, l’interface prend en charge la saisie semi-automatique des commandes Microsoft® IntelliSense®.

Essayer

Pour voir la classe NET_Temperature en action, procédez comme suit :

  1. Appuyez sur F5 pour démarrer le projet.
  2. Entrez 95 dans la zone de texte Fahrenheit, puis cliquez sur Convertir en C. La zone Celsius doit remplir avec la valeur 35.
  3. Entrez -14 dans la zone Celsius, puis cliquez sur Convertir en F. La zone Fahrenheit doit remplir avec la valeur 6,8.
  4. Fermez le formulaire pour arrêter le projet.

Nouveautés de Visual Basic 6.0

Bien entendu, l’ensemble du processus d’appel des composants .NET à partir de Visual Basic 6.0 est nouveau, car .NET n’existait pas lors de la publication de Visual Basic 6.0. Visual Basic 6.0 a la possibilité de créer plusieurs composants connectés par des appels COM, et les CCW .NET font en sorte que les appels .NET fonctionnent comme des appels COM. L’avantage de l’ensemble du processus est que vous n’avez pas besoin de risquer la sécurité et la stabilité des composants .NET pour les utiliser à partir du code COM. En appelant via le CLR, les CCW offrent toujours à vos composants .NET tous les avantages du code managé, quel que soit l’endroit où vous utilisez les composants .NET.

Résumé

Bien que .NET soit un environnement de développement entièrement nouveau, les concepteurs n’ont pas ignoré le problème de compatibilité avec le code existant. En construisant correctement vos composants .NET et en utilisant des outils tels que sn, tlbexp, regasm et gacutil, vous pouvez exposer des classes d’un assembly .NET aux clients COM.

Appeler un composant .NET à partir d’un composant COM n’est pas un exercice trivial. Comme vous l’avez vu dans ce document, vous devez apporter des modifications explicites au code de votre composant .NET pour activer ce scénario. Toutefois, les modifications sont mineures et il existe certainement des avantages à permettre aux clients COM d’appeler des serveurs .NET. Si vous migrez une application complexe de COM vers .NET un composant à la fois, les techniques décrites dans ce document sont essentielles.

À propos de l’auteur

Mike Gunderloy écrit sur les logiciels et élève des poulets dans l’est de l’État de Washington. Il est co-auteur du Manuel du développeur Access 2002 et auteur du Guide to OLAP de SQL Server Développeur avec Analysis Services, tous deux de Sybex. Il écrit du code pour les produits Microsoft depuis l’ère préhistorique pré-Windows, et n’a pas l’intention de s’arrêter de sitôt.

À propos d’Informant Communications Group

Informant Communications Group, Inc. (www.informant.com) est une société de médias diversifiée axée sur le secteur des technologies de l’information. Spécialisée dans les publications de développement de logiciels, les conférences, l’édition de catalogues et les sites Web, ICG a été fondée en 1990. Avec des bureaux dans le États-Unis et au Royaume-Uni, ICG a été un intégrateur de contenu médiatique et marketing respecté, répondant ainsi à l’appétit croissant des professionnels de l’informatique pour des informations techniques de qualité.

Copyright © 2002 Informant Communications Group et Microsoft Corporation

Modification technique : PDSA, Inc. et KNG Consulting