Vous êtes sur la page 1sur 14

1

UtilisationdeCOMetInteroprabilit

UtilisationdeCOMetInteroprabilit
Sommaire
UtilisationdeCOMetInteroprabilit ................................................................................................ 1 1 2 Introduction.....................................................................................................................................2 LescomposantsCOMetlecodenonmanag................................................................................ 3 2.1 2.2 2.3 UtilisationdesobjetsCOM...................................................................................................... 3 GestiondesexceptionsCOM.................................................................................................. 5 UtilisationdecodenonmanagsanslescomposantsCOM..................................................5 LesbasesdeP/Invoke..................................................................................................... 5 Conversionsdedonnes:LeMarshaling........................................................................ 8 Complments................................................................................................................ 11

2.3.1 2.3.2 2.3.3 3 4

Interoprabilitducode.NET....................................................................................................... 12 Conclusion.....................................................................................................................................14

18aot2008

UtilisationdeCOMetInteroprabilit

1 Introduction
Dans le chapitre 8, nous avions vu comment charger du code crit pour fonctionner avec le .NET Framework dans notre application. Cela nous permettait de lancer d'autres applications .NET partird'uneapplication.NET. Seulement, il est possible que nous ayons dvelopper des applications en utilisant un autre systmequele.NETFramework.

Pour cela, nous utiliserons un type d'assembly particulier : Les objets COM. Les objets COM sont des programmes cris en code dit nonmanag ; c'estdire qu'ils n'utilisent pas le systme de gestiondesressourcesproposparleCLRduFramework.NET. Dans cette partie, nous verrons comment importer des objets COM dans notre projet et commentseservird'applicationcritesencodemanagdansdesapplicationsencodenonmanag. 18aot2008

UtilisationdeCOMetInteroprabilit

2 LescomposantsCOMetlecodenonmanag
Les composants COM (Components Object Model) permettent aux applications prvues pour fonctionner avec le .NET Framework d'interagir avec des applications dites nonmanages. Ces applications nonmanages sont toutes les applications qui n'utilisent pas la CLR du .NET. Leur type degestiondesressourcesestpropreaudveloppeurquilesacres.

2.1 UtilisationdesobjetsCOM
Pour pouvoir utiliser un composant COM dans vos applications, il doit tre enregistr dans la base de registre Windows. La plupart des logiciels enregistrent automatiquement leur composants COM dans la base de registre (Microsoft Office, Adobe Acrobat Reader, 7zip). Cependant, vous pourriez vouloir enregistrer vos propres crations. Pour cela, vous pouvez ouvrir une invite de commande de Windows et saisir la commande "regsvr32 "nom_de_la_dll.dll" " en remplaant <nom_de_la_dll>parlenomdevotreDLLenregistrer:

Note : Si vous souhaitez ne plus utiliser votre composant COM, vous pouvez galement le ds enregistrer en utilisant le commutateur "/u" : regsvr32 /u "nom_de_la_dll.dll". Vous pouvez obtenir la liste des commutateurs disponible juste en saisissant "regsvr32". Un message d'erreur s'affichera aveclalistedescommutateursdisponibles. 18aot2008

UtilisationdeCOMetInteroprabilit

Pour utiliser votre composant COM dans vos codes, vous pouvez soit passer par du code en utilisant les outils de System.Runtime.InteropService (ce qui n'est pas forcment recommand car c'estunesourceimportanted'erreurs),soitpasserparl'outild'importationVisualStudio (Seulecette mthodeseraexpliqueici). Pour importer votre composant COM, vous faites comme si vous importiez une assembly dans votreprojetsaufquevousslectionnerezl'onglet"COM":

Vousn'avezplusqu'slectionnerlecomposantquevoussouhaitezimporteretvalider. Vous pouvez galement utiliser loutil en ligne de commande TlbImp.exe dans linvite de commandedeVisualStudio.CeluicivatransformerladlldevotreobjetCOMenassembly.NET,vous naurezplusquajouterunerfrenceverslassemblycre. Pourtransformervotredllvoicilacommande: tlbimpvotre_dll.dll Ou tlbimpvotre_dll.dll/out:nouveau_nom.dll La premire va crer une assembly possdant le mme nom que votre dll, la seconde vous permetdechoisirlenomdelassembly. Pour vous donner un exemple, nous allons crer une application qui va lancer la lecture d'une piste audio en utilisant Windows Media Player. Pour cela, importez le composant COM nomm "Windows Media Player" et qui se situe "C:\Windows\system32\wmp.dll". Ensuite, vous saisirez le codesuivant:
'VB Imports WMPLib Module partie1 Dim player As WMPLib.WindowsMediaPlayer Sub Main() player = New WindowsMediaPlayer() player.openPlayer("ftp://ftp2.mp3trazaac.com/mptrazaac/The maze.mp3") End Sub End Module

18aot2008

UtilisationdeCOMetInteroprabilit

//C# using WMPLib; public static WindowsMediaPlayer player; static void Main(string[] args) { player = new WindowsMediaPlayer(); player.openPlayer("ftp://ftp2.mp3trazaac.com/mptrazaac/The maze.mp3"); }

Ce code se contente de crer une nouvelle instance du lecteur Windows Media Player et de lancerlalectured'unepisteMP3. Malgr les efforts effectus pour que linteroprabilit avec COM soit la plus performante et transparentepossible,ilexistedeslimitesquilestncessairedeconnaitre. Tout dabord les membres statiques ne sont pas supports, d aux diffrences de type videntesentrele.NETetlesobjetsCOM. Ensuite, vous ne pouvez pas utiliser de constructeur avec des paramtres, tous vos constructeursdoiventtreceuxpardfauts. Lhritage est galement limit, si dans une classe hrite certains membres masquent les membresdebases,vousserezincapabledappelerlesmembresdebases. Enfin, linteroprabilit entre .NET et COM utilisant le registre Windows, elle ne fonctionne quesousWindows.

2.2 GestiondesexceptionsCOM
Lorsque vos applications sont cres pour fonctionner avec le Framework .NET, le systme d'exception utilise un systme conforme avec le CLS (Common Language Specifications). Mais lorsque vous excutez une application COM, rien ne garanti que celleci soit galement conforme avecleCLS. Depuis la version 2.0 du Framework, le CLR instancie indiffremment la classe Exception, que a soit pour une exception conforme avec CLS ou non. Ainsi, vous pouvez grer vos erreurs de la mmefaonquepourducodemanag;unsimplebloctrycatchsuffira.

2.3 UtilisationdecodenonmanagsanslescomposantsCOM
Nous avions vu dans la partie prcdente comment utiliser des objets COM dans vos assemblies. Il peut arriver que le composant COM englobant un code non manag n'existe pas, soit parce quil est dprci soit parce que le code n'a pas t port. Nous allons donc devoir utiliser dautresoutilsduFrameworkpourimporteretutiliserducodenonmanag. 2.3.1 LesbasesdeP/Invoke Loutil principal pour manipuler du code manag est Platform Invoke (ou P/Invoke), il est situ danslespacedenomSystem.Runtime.InteropServices. Pour utiliser P/Invoke, nous allons utiliser conjointement un attributet le mot clef extern ou SharedenVB.NET:

18aot2008

UtilisationdeCOMetInteroprabilit

'VB <DllImport("ma.dll")> _ Private Shared Function MaMethode() As Int32 //C# [DllImport("ma.dll")] private static extern Int32 MaMethode();

Lattribut va se charger dimporter un membre de la Dll, vous devez le placer devant votre mthodeouunparamtre. Lemotclefextern/Sharedluipermetdedfinirquenousallonsutiliserunemthodeexterne lassembly et que celleci se situe dans la dll importe. Vous devez imprativement respecter la signaturedelamthode,vousdevezdoncconnatrelasignaturedelamthodedansladllimport! Voiciunexemple dutilisation.NousallonsnousservirdelAPIWin32qui permetla manire des Windows Form dafficher des fentres ou dessiner des formes mais avec du code non manag .NET. Danscecode,nousallonssimplementafficheruneMessageBox:
'VB Imports System.Runtime.InteropServices Imports System.Text Module partie13 Class Win32Invoke Private Const buffer As Int32 = 256 <DllImport("user32.dll")> _ Private Shared Function GetForegroundWindow() As IntPtr End Function <DllImport("user32.dll")> _ Private Shared Function MessageBox(ByVal hWnd As IntPtr, ByVal texte As StringBuilder, ByVal titre As StringBuilder, ByVal constantes As Int32) As Int32 End Function Public Shared Sub Afficher() Dim texte As StringBuilder = New StringBuilder(buffer) texte.Append("Bienvenue dans ma Message Box") Dim titre As StringBuilder = New StringBuilder(buffer) titre.Append("Message Box") Dim fenetre As IntPtr = GetForegroundWindow() MessageBox(fenetre, texte, titre, 4) End Sub End Class Sub Main() Win32Invoke.Afficher() End Sub End Module

18aot2008

UtilisationdeCOMetInteroprabilit

//C# using System.Runtime.InteropServices; static class Win32Invoke { private const Int32 buffer = 256; [DllImport("user32.dll")] private static extern IntPtr GetForegroundWindow(); [DllImport("user32.dll")] private static extern Int32 MessageBox(IntPtr hWnd, StringBuilder texte, StringBuilder titre, Int32 constantes); public static void Afficher() { StringBuilder texte = new StringBuilder(buffer); texte.Append("Bienvenue dans ma Message Box"); StringBuilder titre = new StringBuilder(buffer); titre.Append("Message Box"); IntPtr fenetre = GetForegroundWindow(); MessageBox(fenetre, texte, titre, 4); } } static void Main(string[] args) { Win32Invoke.Afficher(); }

Nous avons cre une classe statique Win32Invoke, celleci est charge de factoriser le code permettantdaffichernotreMessageBox. A lintrieur nous allons importer les deux mthodes permettant dafficher la MessageBox, la premire,GetForegroundWindowretourneun pointeurversla fentre principale,ou,commedans notrecassilnyapasdefentreprincipale,celapointeversunevaleurnull. Notre deuxime mthode permet dafficher la MessageBox , nous avons respect sa signature conformmentunedocumentationtrouvenligne. EnsuitedansunemthodeAffichernousappelonsnosdeuxmthodes. NousutilisonsdesStringBuilderpluttquedesStringcarilsfonctionnentdefaondynamique, etsontdoncplusperformantquandonutiliseducodenonmanag. Note : Vous pourrez trouver les prototypes des mthodes de ces API en allant sur le MSDN danslasectionWin32andCOMdevelopment.

18aot2008

UtilisationdeCOMetInteroprabilit

Nous avons dans notre exemple encapsul le code import dans une classe et une mthode afin de simplifier la rutilisation du code non manag. Cest une bonne pratique car elle va vous permettre dimporter du code non manag sans perturber les autres dveloppeurs qui pourront utiliserseulementducodemanagetnedevrontpasapprendretouteslesficellesdeP/Invoke. FactoriserlecodedansuneclassevaaussivouspermettredutiliserlessubtilitsduC#afin de limiter les erreurs de type induit par des langages trop permissifs. En utilisant par exemple les genericsvousvousassurezderespecterlasignaturedunemthode. Conversionsdedonnes:LeMarshaling Nous avons vu prcdemment comment utiliser du code non manag, mais nous avons un petit peu rus pour cela. En effet si vous comparez la signature de la mthode MessageBox et celle que nous avons dfinit, elle est un petit peu diffrente. Nous utilisons par exemple des StringBuilder laplacedeLPCTSTRetInt32laplacedeUINT. LeMarshalingvanouspermettredanslessentieldeconvertirlestypesdedonnesentrecode managetnonmanag. Il est trs important que vous utilisiez le Marshaling car passer des types manags aux types nonmanagspeutinduiredegraveserreurs. Afinde convertirdes typesdedonnessimple nous allonsutiliserlattribut MarshalAs.Celuici peutsappliqueruntypederetour,unevariableouunparamtredefonction. NousavonspourlexemplemodifinotreprcdentexempleenutilisantleMarshaling: 2.3.2

18aot2008

UtilisationdeCOMetInteroprabilit

'VB Class Win32Invoke Private Const buffer As Int32 = 256 <MarshalAs(UnmanagedType.LPStr)> _ Private texte As StringBuilder <MarshalAs(UnmanagedType.LPStr)> _ Private titre As StringBuilder <DllImport("user32.dll")> _ Private Shared Function GetForegroundWindow() As IntPtr End Function <DllImport("user32.dll")> _ Private Shared Function MessageBox(ByVal hWnd As IntPtr, <MarshalAs(UnmanagedType.LPStr)> ByVal texte As StringBuilder, <MarshalAs(UnmanagedType.LPStr)> ByVal titre As StringBuilder, ByVal constantes As Int32) As Int32 End Function Public Shared Sub Afficher() Dim texte As StringBuilder = New StringBuilder(buffer) texte.Append("Bienvenue dans ma Message Box") Dim titre As StringBuilder = New StringBuilder(buffer) titre.Append("Message Box") Dim fenetre As IntPtr = GetForegroundWindow() MessageBox(fenetre, texte, titre, 4) End Sub End Class

18aot2008

10

UtilisationdeCOMetInteroprabilit

//C# static class Win32Invoke { private const Int32 buffer = 256; [MarshalAs(UnmanagedType.LPStr)] private static StringBuilder texte; [MarshalAs(UnmanagedType.LPStr)] private static StringBuilder titre; [DllImport("user32.dll")] private static extern IntPtr GetForegroundWindow(); [DllImport("user32.dll")] private static extern Int32 MessageBox(IntPtr hWnd, [MarshalAs(UnmanagedType.LPStr)] StringBuilder texte, [MarshalAs(UnmanagedType.LPStr)] StringBuilder titre, Int32 constantes); public static void Afficher() { texte = new StringBuilder(buffer); texte.Append("Bienvenue dans ma Message Box"); titre = new StringBuilder(buffer); titre.Append("Message Box"); IntPtr fenetre = GetForegroundWindow(); MessageBox(fenetre, texte, titre, 4); } }

Nous avons donc utilis lattribut MarshalAs devant nos attributs texte et titre, ainsi que devant le deuxime et troisime paramtre de MessageBox. Si nous utilisons un type incompatible, lersultatserasoitimprvisible,soitilengendrerauneexception. Grce lintelisense de Visual Studio, vous pouvez connaitre lensemble des types disponibles entapantUnmanagerTypesuivitdunpoint.VouspouvezgalementvousrendresurMSDN. Enfin, nous navons prsent ici que le Marshaling de type de donnes simple, vous trouverez unbonnombredexemplesetdetutoriauxsurleMarshalingsurMSDN. 18aot2008

11

UtilisationdeCOMetInteroprabilit

Complments Nous avons prsent une introduction la gestion du code non manag en .NET, vous trouverezdenombreusesressourcessurinternetpourallerplusloin. Sacheznanmoinsquevouspourrezutiliserlaplupartdesoutilsdu.NETpourgrervotrecode manag,Gnrics,Collections,maisaussidelegates(pourlescallback)oummelesexceptions. Enfin, veillez faire attention lorsque vous utilisez du code non manag. Si les performances sonttoutfaithonorables,onnepeutpasendireautantdelascuritducodeetdesproblmesde typage (surtout dans les langages trs permissifs comme le C ou le C++). Testez donc bien vos codes, analysezles, et prenez connaissance dun maximum dinformation grce aux documentations des codesnonmanags. Cela tant dit, si vous dveloppez avec rigueur, il ny a pas de raison de sen priver. En effet, vousallezpouvoirutiliserdsprsentnimportequelleDLLnonmanagavecvotrecodemanaget ainsirendrecompatibledeslibrairiessympathiquestellesqueSDL,oubienencoreHavok. 18aot2008

2.3.3

12

UtilisationdeCOMetInteroprabilit

3 Interoprabilitducode.NET
DanslapremirepartienousavonsvucommentimporterunobjetCOMdansvotrecode.NET et ainsi permettre dutiliser le code dapplications ou de librairie qui ne sont pas du .NET dans vos applications.NET.Nousallonsmaintenantvoirleffetinverse,c'estdiretransformervosassemblies detellemanirecequevouspuissiezlesutiliserdansvosobjetsCOM. Pour rendre vos assemblies interoprable avec des objets COM, il existe un manageur capable defaireinterfaceentreuneassembly.NETetunobjetCOM.CetteinterfacesenommeCOMCallable Wrapper (CCW). Elle va se charger de distribuer votre assembly sous forme marshalise aux diffrentsobjetsCOM. Pour rendre votre assembly utilisable par des objets COM, cest du ct de Visual Studio que nousallonstravailler. ToutdabordvousdevrezcrerunprojetBibliothquedeclasses:

Ensuite crez les classes que vous souhaitez rendre compatible, par exemple une classe personnagecontenanttroisattributsettroisproprits. Enfin, fates un clic droit sur votre projet, puis proprit. Dans le panneau de configuration ainsiouvert,cliquezsurGnrerdanslabarredegauche:

Enfinenbasdelapage,cliquezsurInscrirepourCOMInterop:

Vous pouvez maintenant gnrer votre projet. Une dll est maintenant cre, vous allez pouvoir lafaireinteragiravecvoscomposantsCOM.

18aot2008

13

UtilisationdeCOMetInteroprabilit

Quelques Attributs vont rendre visibles ou non certaines parties du code. Pour cela, nous allonsutiliserlesespacesdenometlattributsuivant:
'VB ' Espaces de nom : Imports System.Runtime.CompilerServices Imports System.Runtime.InteropServices ' Attribut : <ComVisible(boolen)> //C# //Espaces de nom : using System.Runtime.CompilerServices; using System.Runtime.InteropServices; //Attribut : [ComVisible(boolen)]

Lattribut ComVisible peut tre plac devant vos classes et vos membres de classes, si vous voulez masquer une partie des membres, vous devrez rendre votre classe non visible puis faire une listeblanchedesmembresvisibles. Sachez enfin que votre code doit respecter certaines conventions afin que lacompatibilit soit bonne. Votre classe devra comporter au moins un constructeur sans paramtre et seules les classes etmembrespubliquespeuventtrevisibles. 18aot2008

14

UtilisationdeCOMetInteroprabilit

4 Conclusion
Aucoursdecechapitre,vousavezpuconstaterlarellesimplicitd'utilisationdescodesnon managsdansvosapplications.NET Alafindecechapitre,vousdevriezpouvoir: ImporterunobjetCOM,commentlesutiliseretcommentutiliserdesapplications.NET dansdescodesnonmanags. GrerlesexceptionsdescomposantsCOM. UtiliserdescodesnonmanagssanspasserparlescomposantsCOM. Danstouslescas,leMSDNpeutvousapporterunsoutientdedveloppementnonngligeable :

18aot2008