Utilisation de serveurs COM natifs à partir du .NET
Mise à jour : novembre 2007
Cette section décrit les options disponibles pour utiliser des composants COM existants d'applications .NET et souligne les avantages et les inconvénients de chacune des approches. En général, la méthode recommandée est l'interopérabilité C++ (C++ Interop).
Utilisation de TLBIMP
L'outil Kit de développement logiciel (SDK) Windows Type Library Importer (Tlbimp.exe) expose une bibliothèque de types COM en tant qu'assembly nommé assembly d'interopérabilité. Cet assembly définit des équivalents managés, ou wrappers, pour chaque interface COM dans une bibliothèque de types donnée.
Lorsque les méthodes de l'assembly d'interopérabilité sont appelées, une transition de managé à non managée est opérée et le contrôle est passé au composant COM. De même, lorsque la fonction COM non managée retourne, une transition de non managé à managé est opérée. Par défaut, l'absence d'échec est vérifiée dans COM HRESULT, et une exception est levée si HRESULT n'a pas abouti. De même, l'initialisation d'un composant COM et les requêtes d'interface sont exécutées par l'assembly d'interopérabilité et par conséquent masquées pour le code appelant.
Les assemblys d'interopérabilité ne remplacent pas les composants COM qu'ils représentent ; les fonctions COM non managées restent dans le composant COM, et celui-ci doit donc être installé et enregistré sur les ordinateurs cible, sinon les appels à l'assembly d'interopérabilité échouent.
Utiliser Tlbimp est la façon la plus simple d'utiliser un composant COM depuis le code managé, mais cela comporte quelques inconvénients sérieux, surtout pour les interfaces COM grandes et/ou complexes. Ces inconvénients sont les suivants :
Tlbimp génère des interfaces managées pour chaque interface COM dans la bibliothèque de types. Il n'y a aucun moyen de réprimer ce comportement, si bien que les assemblys résultants peuvent être très volumineux. (Par exemple, l'assembly d'interopérabilité généré par Tlbimp pour Mshtml.dll fait plus de 8 Mo). Il n'y a également aucun moyen de masquer une interface uniquement destinée à être utilisée au sein du composant COM.
Tlbimp prend en charge un nombre limité de types de données. Les types qui ne sont habituellement pas pris en charge sont importés dans le monde managé en tant que type IntPtr générique de type non sécurisé, ce qui exige d'utiliser un code de marshaling fastidieux et faillible pour utiliser l'assembly, sachant en outre qu'il arrive à Tlbimp.exe d'être totalement incapable d'exposer les membres d'une interface.
Tlbimp génère un assembly d'interopérabilité séparé, qui doit être déployé avec l'application finale.
Si ces inconvénients sont acceptables, consultez un exemple dans Comment : utiliser des serveurs COM natifs avec TLBIMP.
Modification du MSIL
Les inconvénients de Tlbimp peuvent être quelque peu atténués en désassemblant l'assembly d'interopérabilité (à l'aide du MSIL Disassembler (Ildasm.exe)), en modifiant le MSIL pour supprimer les définitions d'interface inutiles et remplacer les types d'argument, puis en réassemblant le MSIL avec l'Assembleur MSIL (Ilasm.exe). Ce processus est sujet aux erreurs et requiert la connaissance de MSIL, des types non managés et des types .NET. En outre, il faut le recommencer si les interfaces COM sont mises à jour.
C++ Interop
Les inconvénients de Tlbimp (et de la modification de code MSIL) peuvent être totalement évités en Visual C++ car, contrairement à Visual Basic et Visual C#, Visual C++ peut utiliser directement les objets COM à l'aide des mécanismes COM habituels (tels que CoCreateInstance et QueryInterface). En effet, grâce aux fonctionnalités d'interopérabilité C++, le compilateur insère automatiquement le code de transition pour se déplacer entre fonctions managées et non managées.
Grâce à l'interopérabilité C++, les composants COM peuvent être utilisés comme ils le sont normalement, ou encapsulés dans des classes C++. Ces classes wrapper sont appelées wrappers WRC personnalisés, ou CRCW, et possèdent deux avantages, outre celui d'utiliser directement COM dans le code de l'application :
La classe résultante peut être utilisée à partir de langages autres que Visual C++.
Les détails de l'interface COM peuvent être masqués au code client managé. Les types de données .NET peuvent être utilisés au lieu de types natifs, et les détails de marshaling de données peuvent être exécutés de façon transparente à l'intérieur du CRCW.
On trouvera une description de l'utilisation de Visual C++ pour encapsuler les interfaces COM dans Comment : utiliser des serveurs COM natifs avec CRCWs.
Que COM soit utilisé directement ou au travers d'un CRCW, les types d'argument autres que des types simples blittables doivent être marshalés. Pour plus d'informations sur le marshaling de données, consultez Utilisation de l'interopérabilité C++ (PInvoke implicite).
Remarque : |
---|
Les applications MFC doivent être initialisées en tant que threads STA (single threaded apartment). Si vous appelez CoInitializeEx dans votre substitution de InitInstance, spécifiez COINIT_APARTMENTTHREADED (plutôt que COINIT_MULTITHREADED). Pour plus d'informations, consultez l'article PRB: MFC Application Stops Responding When You Initialize the Application as a Multithreaded Apartment (828643) à l'adresse https://support.microsoft.com/default.aspx?scid=kb;en-us;828643. |