<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Blog de Nico-pyright(c) &#187; C++ Interop</title>
	<atom:link href="https://blog.developpez.com/nico-pyright/pcategory/c-interop/feed" rel="self" type="application/rss+xml" />
	<link>https://blog.developpez.com/nico-pyright</link>
	<description></description>
	<lastBuildDate>Mon, 08 Apr 2013 09:26:35 +0000</lastBuildDate>
	<language>fr-FR</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=4.1.42</generator>
	<item>
		<title>[C++/CLI] Comment créer un Wrapper C++/CLI, exemple de compression en .Cab</title>
		<link>https://blog.developpez.com/nico-pyright/p6460/ccli/c_cli_comment_creer_un_wrapper_c_cli_exe</link>
		<comments>https://blog.developpez.com/nico-pyright/p6460/ccli/c_cli_comment_creer_un_wrapper_c_cli_exe#comments</comments>
		<pubDate>Sat, 27 Sep 2008 08:58:09 +0000</pubDate>
		<dc:creator><![CDATA[nico-pyright(c)]]></dc:creator>
				<category><![CDATA[C++ Interop]]></category>
		<category><![CDATA[C++/CLI]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[on me demande souvent comment créer un wrapper C++/CLI &#8230; Je vais, dans ce post, vous guider dans la création d&#8217;un tel wrapper. Pour l&#8217;exemple, je vais utiliser la très bonne bibliothèque de compression en .Cab, créée par Elmue sur CodeProject. Cette bibliothèque possède une version C++ et une version .Net, cette dernière ayant été créé avec le Managed C++ de Visual Studio 2002, je vais vous montrer comment on peut encapsuler la version C++ [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>on me demande souvent comment créer un wrapper C++/CLI &#8230;</p>
<p>Je vais, dans ce post, vous guider dans la création d&rsquo;un tel wrapper.<br />
Pour l&rsquo;exemple, je vais utiliser la <a href="http://www.codeproject.com/KB/files/CABCompressExtract.aspx">très bonne bibliothèque de compression en .Cab</a>, créée par Elmue sur CodeProject.</p>
<p>Cette bibliothèque possède une version C++ et une version .Net, cette dernière ayant été créé avec le Managed C++ de Visual Studio 2002, je vais vous montrer comment on peut encapsuler la version C++ pure dans un wrapper C++/CLI afin de l&rsquo;utiliser avec vos projets .Net.</p>
<p><span id="more-36"></span></p>
<p>Pour cet exemple, je vais encapsuler uniquement la compression, donc je vais soulager le projet C++ de quelques fichiers et je vais les modifier pour retirer les références à ces fichiers inutiles.</p>
<p>J&rsquo;ai donc cette liste de fichier qui vont me servir :<br />
&#8211; Blowfish.h<br />
&#8211; Compress.h<br />
&#8211; Error.h<br />
&#8211; File.h<br />
&#8211; Map.h<br />
&#8211; String.h</p>
<p>(notez que j&rsquo;ai renommé les fichiers .hpp en .h parce que j&rsquo;aime mieux &#8230;)</p>
<p>Je créé ensuite un nouveau projet CLR : Class Library que j&rsquo;appelle CabUtil (il est donc <a href="http://dotnet.developpez.com/faq/cppcli/?page=compilationmode#clronly">compilé avec l&rsquo;option /clr</a>).<br />
J&rsquo;y ajoute les fichiers précédemment cités, je compile &#8230; et c&rsquo;est presque terminé !<br />
La fonctionnalité <a href="http://nico-pyright.developpez.com/tutoriel/vc2005/interop/">nommée C++ Interop</a> a fait tout le boulot pour nous. Elle a compilé du code natif dans notre assembly .Net.</p>
<p>Passons désormais à la création du wrapper C++/CLI, qui fera office de wrapper et de façade en même temps.</p>
<p>Je créé une nouvelle classe, que j&rsquo;appelle CabUtil.</p>
<p>Ici, je n&rsquo;ai pas grand chose à wrapper, mais nous allons le faire quand même. On remarque qu&rsquo;on a besoin d&rsquo;un char * qui représente la clé de cryptage du .Cab.</p>
<p>Créons donc un membre privé de type char *</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">char * s8_EncryptionKey;</div></div>
<p>Je vais lui affecter une valeur par défaut dans mon constructeur :</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">CabCompress() <br />
{ <br />
&nbsp; s8_EncryptionKey = new char[73]; <br />
&nbsp; strcpy(s8_EncryptionKey, &quot;&quot;); <br />
}</div></div>
<p>Maintenant, on va créer une propriété qui va exposer une String ^ .Net et qui se chargera de convertir en char * :</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">property String ^EncryptionKey <br />
{ <br />
&nbsp; void set(String ^value) <br />
&nbsp; { <br />
&nbsp; &nbsp; if (value-&gt;Length &gt; 72) <br />
&nbsp; &nbsp; &nbsp; value = value-&gt;Substring(0, 72); <br />
&nbsp; &nbsp; char* temp = static_cast&lt;char *&gt;(Marshal::StringToHGlobalAnsi(value).ToPointer()); <br />
&nbsp; &nbsp; strcpy(s8_EncryptionKey, temp); <br />
&nbsp; &nbsp; Marshal::FreeHGlobal(safe_cast&lt;IntPtr&gt;(temp)); <br />
&nbsp; } <br />
}</div></div>
<p>Note : la clé ne peut pas dépasser 72 caractères.</p>
<p>Bien sur, il ne faudra pas oublier de désallouer le char * dans les destructeurs et finalizers :</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">~CabCompress() <br />
{ <br />
&nbsp; delete s8_EncryptionKey; <br />
&nbsp; s8_EncryptionKey = NULL; <br />
} <br />
&nbsp;<br />
protected: <br />
&nbsp; !CabCompress() <br />
&nbsp; { <br />
&nbsp; &nbsp; delete s8_EncryptionKey; <br />
&nbsp; &nbsp; s8_EncryptionKey = NULL; <br />
&nbsp; }</div></div>
<p>Je vais maintenant passer à l&rsquo;écriture d&rsquo;une méthode qui va compresser une liste de fichier, cette méthode étant une façade pour un algorithme un peu plus complexe.<br />
Il s&rsquo;agit de la méthode :</p>
<p><code class="codecolorer text default"><span class="text">void CompressFileList(IDictionary&lt;String^, String^&gt;^ fileList, String ^compressFile)</span></code></p>
<p>Elle prend en paramètre un dictionnaire qui va contenir le nom du fichier à compresser et sa destination dans l&rsquo;arborescence du .Cab. Le deuxième paramètre est le fichier archive de destination.</p>
<p>Il y a dans cette méthode quelques conversions de String ^ en char *, mais nous n&rsquo;allons pas nous attarder, vu qu&rsquo;on a déjà vu le principe plus haut.<br />
L&rsquo;autre élément intéressant est le mapping d&rsquo;une callback native en delegate .Net. Nous allons créer un événement pour être informé de la mise à jour du status de la compression.</p>
<p>On avait en C++, la définition suivante pour gérer la callback :</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">Cabinet::CCompress::kCallbacks k_ComprCallbacks; <br />
k_ComprCallbacks.f_UpdateStatus &nbsp; = &amp;CMain::OnUpdateStatus;</div></div>
<p>avec la méthode statique associée :</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">static int CMain::OnUpdateStatus(UINT typeStatus, Cabinet::CCompress::kCurStatus *pk_CurStatus, void *p_Param) <br />
{ <br />
... <br />
}</div></div>
<p>pour wrapper ceci, nous allons créer un delegate, dans les membres privés :</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">[UnmanagedFunctionPointer(CallingConvention::StdCall)] <br />
delegate int WrapperUpdateStatusHandler(UINT typeStatus, Cabinet::CCompress::kCurStatus *pk_CurStatus, void *p_Param); <br />
WrapperUpdateStatusHandler ^UpdateStatusDelegate;</div></div>
<p>Notez que le delegate a bien sur la même signature que la méthode OnUpdateStatus.</p>
<p>Dans notre méthode, on pourra instancier notre delegate ainsi :</p>
<p><code class="codecolorer text default"><span class="text">UpdateStatusDelegate = gcnew WrapperUpdateStatusHandler(this, &amp;CabCompress::UpdateStatus);</span></code></p>
<p>qui est raccroché à la méthode </p>
<p><code class="codecolorer text default"><span class="text">static int UpdateStatus(UINT typeStatus, Cabinet::CCompress::kCurStatus *pk_CurStatus, void *p_Param)</span></code></p>
<p>(les observateurs auront noté que j&rsquo;ai changé le nom de la méthode C++, qui au passage, n&rsquo;est plus statique)</p>
<p>Ensuite on utilise GetFunctionPointerForDelegate pour raccrocher ce delegate à la callback en C++</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">IntPtr p = Marshal::GetFunctionPointerForDelegate(UpdateStatusDelegate); <br />
k_ComprCallbacks.f_UpdateStatus &nbsp; = (Cabinet::CCompress::kCallbacks::t_UpdateStatus)p.ToPointer(); <br />
i_Compress.SetCallbacks(&amp;k_ComprCallbacks);</div></div>
<p>Maintenant, la méthode UpdateStatus pourra lever l&rsquo;événement suivant (qu&rsquo;on aura défini comme membre public de la classe) :</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">delegate void UpdateStatusHandler(int PercentComplete); <br />
event UpdateStatusHandler ^OnUpdateStatus; <br />
&nbsp;<br />
int UpdateStatus(UINT typeStatus, Cabinet::CCompress::kCurStatus *pk_CurStatus, void *p_Param) <br />
{ <br />
&nbsp; if (pk_CurStatus-&gt;FolderPercent &gt; 0) <br />
&nbsp; &nbsp; OnUpdateStatus(pk_CurStatus-&gt;FolderPercent); <br />
&nbsp; return 0; <br />
}</div></div>
<p>Et voilà, il ne nous reste plus qu&rsquo;à compiler et notre assembly est prête.</p>
<p>Reste à l&rsquo;utiliser dans un programme C#. Pour ce faire, on référence cette assembly dans notre projet, et on peut appeler la méthode de compression ainsi :</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">static void Main() <br />
{ <br />
&nbsp; CabCompress c = new CabCompress(); <br />
&nbsp; c.OnUpdateStatus += c_OnUpdateStatus; <br />
&nbsp; Dictionary&lt;string, string&gt; dictionary = new Dictionary&lt;string, string&gt; <br />
&nbsp; &nbsp; { <br />
&nbsp; &nbsp; &nbsp; {&quot;C:\\test.txt&quot;, &quot;C\\test.txt&quot;}, <br />
&nbsp; &nbsp; &nbsp; {&quot;C:\\temp\\fichier.mp3&quot;, &quot;C\\temp\\fichier.mp3&quot;} <br />
&nbsp; &nbsp; }; <br />
&nbsp; c.CompressFileList(dictionary, &quot;C:\\OutPut_%d.cab&quot;); <br />
} <br />
&nbsp;<br />
static void c_OnUpdateStatus(int PercentComplete) <br />
{ <br />
&nbsp; Console.WriteLine(&quot;Compression : {0} %&quot;, &nbsp;PercentComplete); <br />
}</div></div>
<p>Vous pouvez télécharger les sources de cet exemple : <a href="ftp://ftp-developpez.com/nico-pyright/blog/CabUtil.zip">version zip</a> ou <a href="ftp://ftp-developpez.com/nico-pyright/blog/CabUtil.rar">version rar</a></p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>[C++ Interop] Marshaling d&#8217;un tableau de wchar_t</title>
		<link>https://blog.developpez.com/nico-pyright/p5265/c-interop/c_interop_marshaling_d_un_tableau_de_wch</link>
		<comments>https://blog.developpez.com/nico-pyright/p5265/c-interop/c_interop_marshaling_d_un_tableau_de_wch#comments</comments>
		<pubDate>Thu, 13 Mar 2008 20:00:00 +0000</pubDate>
		<dc:creator><![CDATA[nico-pyright(c)]]></dc:creator>
				<category><![CDATA[C#]]></category>
		<category><![CDATA[C++ Interop]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Suite à une question, voici un exmple pour passer un tableau de wchar_t d&#8217;une DLL C à une application managée (C# par exemple). Soit une dll C qui expose une méthode qui alloue et initialise un wchar_t ** : #include &#60;stdio.h&#62; &#160; extern &#34;C&#34; __declspec(dllexport) void demo(wchar_t ** &#38;tab) { #define SIZE 10 &#160; tab = new wchar_t* [SIZE]; &#160; for (int i = 0; i &#60; SIZE ; i++) &#160; { &#160; &#160; tab[i] [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Suite à une question, voici un exmple pour passer un tableau de wchar_t d&rsquo;une DLL C à une application managée (C# par exemple).<br />
<span id="more-35"></span></p>
<p>Soit une dll C qui expose une méthode qui alloue et initialise un wchar_t ** :</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">#include &lt;stdio.h&gt; <br />
&nbsp;<br />
extern &quot;C&quot; __declspec(dllexport) void demo(wchar_t ** &amp;tab) <br />
{ <br />
#define SIZE 10 <br />
&nbsp; tab = new wchar_t* [SIZE]; <br />
&nbsp; for (int i = 0; i &lt; SIZE ; i++) <br />
&nbsp; { <br />
&nbsp; &nbsp; tab[i] = new wchar_t[20]; <br />
&nbsp; &nbsp; swprintf(tab[i], L&quot;chaine : %i&quot;, i); <br />
&nbsp; } <br />
}</div></div>
<p>et le code C# pour récupérer le tableau de chaine :</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">[DllImport(&quot;demoWchar.dll&quot;)] <br />
public static extern void demo(out IntPtr buff); <br />
&nbsp;<br />
static void Main() <br />
{ <br />
&nbsp; &nbsp; IntPtr test; <br />
&nbsp; &nbsp; demo(out test); <br />
&nbsp;<br />
&nbsp; &nbsp; int tailleTableau = 10; <br />
&nbsp; &nbsp; IntPtr[] tabPointeur = new IntPtr[tailleTableau]; <br />
&nbsp; &nbsp; Marshal.Copy(test, tabPointeur, 0, tailleTableau); <br />
&nbsp; &nbsp; for (int i = 0; i &lt; tailleTableau; i++) <br />
&nbsp; &nbsp; &nbsp; &nbsp; Console.WriteLine(Marshal.PtrToStringUni(tabPointeur[i])); <br />
}</div></div>
<p>La taille d&rsquo;un tableau est toujours problèmatique.<br />
Ici elle est fixée en dur, mais en général, c&rsquo;est une donnée qui transite également dans les paramètres.</p>
<p><a href="ftp://ftp-developpez.com/nico-pyright/blog/demoWchar.rar">Télécharger l&rsquo;exemple complet </a></p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>[C++/CLI] Participez à l&#8217;augmentation de la bibliothèque marshal_as</title>
		<link>https://blog.developpez.com/nico-pyright/p5097/ccli/c_cli_participez_a_l_augmentation_de_la_</link>
		<comments>https://blog.developpez.com/nico-pyright/p5097/ccli/c_cli_participez_a_l_augmentation_de_la_#comments</comments>
		<pubDate>Thu, 14 Feb 2008 20:00:00 +0000</pubDate>
		<dc:creator><![CDATA[nico-pyright(c)]]></dc:creator>
				<category><![CDATA[C++ Interop]]></category>
		<category><![CDATA[C++/CLI]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Une nouveauté dans visual studio 2008 est l&#8217;utilisation du template marshal_as pour faire du marshaling. Incomplète encore à l&#8217;heure actuelle, retrouvez le blog dédié à son enrichissement à cette adresse : http://www.marshal-as.net/ Vous pouvez également envoyer vos contributions à Kate Gregory]]></description>
				<content:encoded><![CDATA[<p>Une nouveauté dans visual studio 2008 est l&rsquo;utilisation du template marshal_as pour faire du marshaling. </p>
<p>Incomplète encore à l&rsquo;heure actuelle, retrouvez le blog dédié à son enrichissement à cette adresse : http://www.marshal-as.net/<br />
Vous pouvez également envoyer vos contributions à Kate Gregory</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>[C++/CLI] Intéropérabilité de structure</title>
		<link>https://blog.developpez.com/nico-pyright/p5013/ccli/c_cli_interoperabilite_de_structure</link>
		<comments>https://blog.developpez.com/nico-pyright/p5013/ccli/c_cli_interoperabilite_de_structure#comments</comments>
		<pubDate>Fri, 01 Feb 2008 21:52:49 +0000</pubDate>
		<dc:creator><![CDATA[nico-pyright(c)]]></dc:creator>
				<category><![CDATA[C#]]></category>
		<category><![CDATA[C++ Interop]]></category>
		<category><![CDATA[C++/CLI]]></category>
		<category><![CDATA[C/C++ - Win32]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Je viens de mettre à jour mon tutoriel sur l&#8217;intéropérabilité où j&#8217;expose une manière plus simple de mettre à jour une structure C native par référence depuis un programme C#. soit la structure C suivante typedef struct { &#160; &#160; int age; &#160; &#160; int taille; &#160; } MASTRUCTURE; et la méthode suivante qui incrémente une structure passée en paramètre : extern &#34;C&#34; __declspec(dllexport) void Inc(MASTRUCTURE * s) &#160; { &#160; &#160; s-&#62;age++; &#160; &#160; [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Je viens de mettre à jour mon <a href="http://nico-pyright.developpez.com/tutoriel/vc2005/interop2/#Lupdatestruct">tutoriel sur l&rsquo;intéropérabilité</a> où j&rsquo;expose une manière plus simple de mettre à jour une structure C native par référence depuis un programme C#.</p>
<p><span id="more-34"></span></p>
<p>soit la structure C suivante</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">typedef struct { &nbsp;<br />
&nbsp; int age; &nbsp;<br />
&nbsp; int taille; &nbsp;<br />
} MASTRUCTURE;</div></div>
<p>et la méthode suivante qui incrémente une structure passée en paramètre :</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">extern &quot;C&quot; __declspec(dllexport) void Inc(MASTRUCTURE * s) &nbsp;<br />
{ &nbsp;<br />
&nbsp; s-&gt;age++; &nbsp;<br />
&nbsp; s-&gt;taille++; &nbsp;<br />
}</div></div>
<p>On peut utiliser les méthodes <strong>PtrToStructure</strong> et <strong>StructureToPtr</strong> pour faire l&rsquo;intéropérabilité, mais on peut également utiliser une méthode très simple en déclarant notre structure avec le mot clé <strong>struct</strong> :</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">[StructLayout(LayoutKind.Sequential)] <br />
public struct MaStructCSharp <br />
{ <br />
&nbsp; public int age; <br />
&nbsp; public int taille; <br />
}</div></div>
<p>Et si on déclare le DllImport avec une référence :</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">[DllImport(&quot;libCStruct.dll&quot;)] <br />
public static extern void Inc(ref MaStructCSharp s);</div></div>
<p>On pourra faire l&rsquo;implémentation de notre code C# ainsi :</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">MaStructCSharp s = new MaStructCSharp(); <br />
s.age = 27; <br />
s.taille = 185; <br />
Inc(ref s); <br />
Console.WriteLine(s.age); <br />
Console.WriteLine(s.taille);</div></div>
<p>Voilà</p>
<p>J&rsquo;en profite pour remercier Mike pour ses remarques constructives sur mon article <img src="https://blog.developpez.com/nico-pyright/wp-includes/images/smilies/icon_smile.gif" alt=":)" class="wp-smiley" /></p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Tutoriel : Introduction à l&#8217;intéropérabilité (partie 2)</title>
		<link>https://blog.developpez.com/nico-pyright/p4448/ccli/tutoriel_introduction_a_l_interoperabili_2</link>
		<comments>https://blog.developpez.com/nico-pyright/p4448/ccli/tutoriel_introduction_a_l_interoperabili_2#comments</comments>
		<pubDate>Sun, 28 Oct 2007 23:00:00 +0000</pubDate>
		<dc:creator><![CDATA[nico-pyright(c)]]></dc:creator>
				<category><![CDATA[C#]]></category>
		<category><![CDATA[C++ Interop]]></category>
		<category><![CDATA[C++/CLI]]></category>
		<category><![CDATA[C/C++ - Win32]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Je vous présente la deuxième partie de mon tutoriel d&#8217;introduction à l&#8217;intéropérabilité. Vous apprendrez comment utiliser des structures C plus ou moins complexes dans un programme C#. Vous apprendrez aussi comment fonctionne COM Interop ainsi que le hosting de CLR afin d&#8217;utiliser des objets .Net dans une application native. Aller au tutoriel d&#8217;introduction à l&#8217;intéropérabilité (partie 2) Bonne lecture]]></description>
				<content:encoded><![CDATA[<p>Je vous présente la deuxième partie de mon tutoriel d&rsquo;introduction à l&rsquo;intéropérabilité.</p>
<p>Vous apprendrez comment utiliser des structures C plus ou moins complexes dans un programme C#. Vous apprendrez aussi comment fonctionne COM Interop ainsi que le hosting de CLR afin d&rsquo;utiliser des objets .Net dans une application native.</p>
<p><a href="http://nico-pyright.developpez.com/tutoriel/vc2005/interop2/">Aller au tutoriel d&rsquo;introduction à l&rsquo;intéropérabilité (partie 2)</a></p>
<p>Bonne lecture</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>L&#8217;avenir de visual c++ ?</title>
		<link>https://blog.developpez.com/nico-pyright/p4059/ccli/l_avenir_de_visual_c</link>
		<comments>https://blog.developpez.com/nico-pyright/p4059/ccli/l_avenir_de_visual_c#comments</comments>
		<pubDate>Thu, 09 Aug 2007 19:00:00 +0000</pubDate>
		<dc:creator><![CDATA[nico-pyright(c)]]></dc:creator>
				<category><![CDATA[C++ Interop]]></category>
		<category><![CDATA[C++/CLI]]></category>
		<category><![CDATA[C/C++ - Win32]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Somasegar nous informe de l&#8217;orientation stratégique de Visual C++. Comme on pouvait s&#8217;en douter, les priorités s&#8217;articulent autour de : l&#8217;augmentation du support sur le développement natif l&#8217;interop pour permettre a des applications natives d&#8217;accéder aux composants des framework.Net (WPF, WCF, &#8230;) que ce soit pour un relooking ou pour tirer parti des avancées du framework. l&#8217;interop en tant que pont entre le monde managé et natif, pour tout ce qui est wrapper. Des perspectives [&#8230;]]]></description>
				<content:encoded><![CDATA[<p><a href="http://blogs.msdn.com/somasegar/default.aspx">Somasegar</a> nous informe de l&rsquo;orientation stratégique de Visual C++.</p>
<p>Comme on pouvait s&rsquo;en douter, les priorités s&rsquo;articulent autour de : </p>
<ul>
<li> l&rsquo;augmentation du support sur le développement natif</li>
<li> l&rsquo;interop pour permettre a des applications natives d&rsquo;accéder aux composants des framework.Net (WPF, WCF, &#8230;) que ce soit pour un relooking ou pour tirer parti des avancées du framework.</li>
<li> l&rsquo;interop en tant que pont entre le monde managé et natif, pour tout ce qui est wrapper.</li>
</ul>
<p>Des perspectives pour le C++/CLI, langage roi de l&rsquo;intéropérabilité&#8230; et pour tout ce qui est natif, le C++ reste le langage de premier choix.</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Comment intercepter des exceptions managées depuis du code natif ?</title>
		<link>https://blog.developpez.com/nico-pyright/p4044/ccli/comment_intercepter_des_exceptions_manag</link>
		<comments>https://blog.developpez.com/nico-pyright/p4044/ccli/comment_intercepter_des_exceptions_manag#comments</comments>
		<pubDate>Tue, 07 Aug 2007 22:00:00 +0000</pubDate>
		<dc:creator><![CDATA[nico-pyright(c)]]></dc:creator>
				<category><![CDATA[C++ Interop]]></category>
		<category><![CDATA[C++/CLI]]></category>
		<category><![CDATA[C/C++ - Win32]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Des fois, il peut etre utile de pouvoir intercepter une exception managée à partir d&#8217;un code natif. Soit le programme suivant qui simule, grace aux pragma unmanaged et managed, une intéraction entre un code natif et un code managé : using namespace System; &#160; void fonctionManagee() { &#160; throw gcnew Exception(&#34;Exception managée&#34;); } &#160; #pragma unmanaged void fonctionNative() { &#160; fonctionManagee(); } #pragma managed &#160; int main() { &#160; fonctionNative(); &#160; return 0; } Si [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Des fois, il peut etre utile de pouvoir intercepter une exception managée à partir d&rsquo;un code natif.</p>
<p>Soit le programme suivant qui simule, grace aux pragma <strong>unmanaged </strong>et <strong>managed</strong>, une intéraction entre un code natif et un code managé :</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">using namespace System; <br />
&nbsp;<br />
void fonctionManagee() <br />
{ <br />
&nbsp; throw gcnew Exception(&quot;Exception managée&quot;); <br />
} <br />
&nbsp;<br />
#pragma unmanaged <br />
void fonctionNative() <br />
{ <br />
&nbsp; fonctionManagee(); <br />
} <br />
#pragma managed <br />
&nbsp;<br />
int main() <br />
{ <br />
&nbsp; fonctionNative(); <br />
&nbsp; return 0; <br />
}</div></div>
<p><span id="more-10"></span></p>
<p>Si on exécute cet exemple, on obtient un crash de l&rsquo;application à cause de la levée d&rsquo;exception dans la méthode managée.</p>
<p>Le premier reflexe est d&rsquo;utiliser un try catch &#8230; mais &#8230; quel type d&rsquo;exception attraper ? Une solution pourrait être de tout attraper, avec une construction de ce genre :</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">void fonctionNative() <br />
{ <br />
&nbsp; try <br />
&nbsp; { <br />
&nbsp; &nbsp; fonctionManagee(); <br />
&nbsp; } <br />
&nbsp; catch (...) <br />
&nbsp; { <br />
&nbsp; &nbsp; std::cout &lt;&lt; &quot;N'importe quelle exception est attrapee, meme managee&quot; &lt;&lt; std::endl; <br />
&nbsp; } <br />
}</div></div>
<p>Cette construction a l&rsquo;avantage de permettre d&rsquo;intercepter l&rsquo;exception levée dans la fonction managée depuis le code natif, mais a l&rsquo;inconvénient de tout intercepter, à cause de la construction <strong>&laquo;&nbsp;&#8230;&nbsp;&raquo;</strong> suivant le catch.</p>
<p>La solution est d&rsquo;utiliser un block <strong>try except</strong>, comme ci-dessous :</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">void fonctionNative() <br />
{ <br />
&nbsp; __try <br />
&nbsp; { <br />
&nbsp; &nbsp; fonctionManagee(); <br />
&nbsp; } <br />
&nbsp; __except(GetExceptionCode() == 0xE0434F4D ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) <br />
&nbsp; { <br />
&nbsp; &nbsp; std::cout &lt;&lt; &quot;Uniquement les exceptions managees sont attrapees&quot; &lt;&lt; std::endl; <br />
&nbsp; } <br />
}</div></div>
<p>0xE0434F4D est le code d&rsquo;erreur SEH correspond. (pour l&rsquo;anectode, 0xE0434F4D correspond à 0xE0+&nbsp;&raquo;COM&nbsp;&raquo; (= &lsquo;àCOM&rsquo;), car à l&rsquo;origine, le CLR a été appelé COM+ 2.0. Le nom du projet a changé mais pas les codes d&rsquo;exception)</p>
<p>L&rsquo;inconvénient est qu&rsquo;on ne peut pas avoir d&rsquo;information sur l&rsquo;exception, comme dans notre cas, le message d&rsquo;exception levé.</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Intéropérabilité de tableau dans une structure, le problème des tableaux à plusieurs dimensions</title>
		<link>https://blog.developpez.com/nico-pyright/p3877/cc-win32/interoperabilite_de_tableau_dans_une_str</link>
		<comments>https://blog.developpez.com/nico-pyright/p3877/cc-win32/interoperabilite_de_tableau_dans_une_str#comments</comments>
		<pubDate>Fri, 29 Jun 2007 19:00:00 +0000</pubDate>
		<dc:creator><![CDATA[nico-pyright(c)]]></dc:creator>
				<category><![CDATA[C++ Interop]]></category>
		<category><![CDATA[C/C++ - Win32]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[On vient de me poser une question : je veux utiliser cette structure en C dans mon programme C# typedef struct &#160; { &#160; int val; &#160; int telfixe[10][2]; } MASTRUCTURETEL; j&#8217;ai un peu modifié l&#8217;exemple pour que ce soit plus simple, mais la question porte sur le tableau à deux dimensions. Alors, comment faire ? Sur l&#8217;exemple de mes précédents billets, je vais créer une dll qui va exporter une fonction qui me retourne [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>On vient de me poser une question :</p>
<p>je veux utiliser cette structure en C dans mon programme C#</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">typedef struct &nbsp;<br />
{ <br />
&nbsp; int val; <br />
&nbsp; int telfixe[10][2]; <br />
} MASTRUCTURETEL;</div></div>
<p>j&rsquo;ai un peu modifié l&rsquo;exemple pour que ce soit plus simple, mais la question porte sur le tableau à deux dimensions.</p>
<p>Alors, comment faire ? <span id="more-32"></span></p>
<p>Sur l&rsquo;exemple de mes précédents billets, je vais créer une dll qui va exporter une fonction qui me retourne une structure :</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">typedef struct &nbsp;<br />
{ <br />
&nbsp; int val; <br />
&nbsp; int telfixe[10][2]; <br />
} MASTRUCTURETEL; <br />
&nbsp;<br />
extern &quot;C&quot; __declspec(dllexport) MASTRUCTURETEL * GetUneStructure() &nbsp;<br />
{ <br />
&nbsp; MASTRUCTURETEL *maStruct = new MASTRUCTURETEL; <br />
&nbsp; for (int i = 0 ; i &lt; 10 ; i++) <br />
&nbsp; &nbsp; for (int j = 0; j &lt; 2 ; j++) <br />
&nbsp; &nbsp; &nbsp; maStruct-&gt;telfixe[i][j] = (i+1)*(j+1); <br />
&nbsp; maStruct-&gt;val = 10; <br />
&nbsp; return maStruct; &nbsp;<br />
}</div></div>
<p>J&rsquo;initialise mon tableau avec un peu n&rsquo;importe quoi, mais bon voila, c&rsquo;est exactement le tableau que je voulais avec les valeurs que je voulais :p</p>
<p>Maintenant, je veux pouvoir l&rsquo;utiliser dans mon programme C#.</p>
<p>Il faut savoir que le marshaleur ne sait pas marshaler des tableaux multi-dimmensionnels, et donc que fatalement, nous allons récupérer un tableau à une seule dimension. Pour ce faire, on crée la structure C# ainsi :</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; &nbsp; [StructLayout(LayoutKind.Sequential)] <br />
&nbsp; &nbsp; public class MaStructTelCSharp <br />
&nbsp; &nbsp; { <br />
&nbsp; &nbsp; &nbsp; &nbsp; public int val; <br />
&nbsp; &nbsp; &nbsp; &nbsp; [MarshalAs(UnmanagedType.ByValArray, SizeConst=10*2, ArraySubType=UnmanagedType.SysInt)] <br />
&nbsp; &nbsp; &nbsp; &nbsp; public int[] telFixe; <br />
&nbsp; &nbsp; }</div></div>
<p>L&rsquo;important est de noter la taille du tableau dans le paramètre SizeConst de l&rsquo;attribut MarshalAs. On lui précise aussi qu&rsquo;on veut récupérer des entiers.</p>
<p>Puis, on récupère la structure ainsi :</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; &nbsp; &nbsp; &nbsp; [DllImport(&quot;testLib.dll&quot;)] <br />
&nbsp; &nbsp; &nbsp; &nbsp; public static extern IntPtr GetUneStructure(); <br />
&nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ... <br />
&nbsp; &nbsp; &nbsp; &nbsp; IntPtr maStructureCUnmanaged = GetUneStructure(); <br />
&nbsp; &nbsp; &nbsp; &nbsp; MaStructTelCSharp maStructureCSharp = new MaStructTelCSharp(); <br />
&nbsp; &nbsp; &nbsp; &nbsp; Marshal.PtrToStructure(maStructureCUnmanaged, maStructureCSharp);</div></div>
<p>Au final donc, on se retrouve avec une structure qui contient un tableau à une dimension au lieu d&rsquo;un tableau à deux dimensions.<br />
C&rsquo;est triste mais c&rsquo;est ainsi.</p>
<p>Rien ne vous empeche de reconstruire éventuellement un tableau à deux dimensions à partir de notre tableau à 1 dimension.</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>COM Interop &#8211; Conserver la signature des méthodes</title>
		<link>https://blog.developpez.com/nico-pyright/p3844/cc-win32/com_interop_conserver_la_signature_des_m</link>
		<comments>https://blog.developpez.com/nico-pyright/p3844/cc-win32/com_interop_conserver_la_signature_des_m#comments</comments>
		<pubDate>Sun, 24 Jun 2007 19:32:15 +0000</pubDate>
		<dc:creator><![CDATA[nico-pyright(c)]]></dc:creator>
				<category><![CDATA[C++ Interop]]></category>
		<category><![CDATA[C/C++ - Win32]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Le billet précédent présente une méthode qui simplifie grandement l&#8217;écriture de notre programme natif qui utilise un objet managé via COM Interop. La contrainte qu&#8217;il rajoute est la transformation des signatures des méthodes à la sauce COM. Ainsi, une méthode : String^ ReadLine(); sera wrappée en HRESULT ReadLine(/*[out,retval]*/ BSTR); Ce qui suggère l&#8217;utilisation de la macro SUCCEEDED pour tester la bonne marche de la fonction. Mais pouvons-nous encore simplifier et se passer de ce type [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Le billet précédent présente une méthode qui simplifie grandement l&rsquo;écriture de notre programme natif qui utilise un objet managé via COM Interop.<br />
La contrainte qu&rsquo;il rajoute est la transformation des signatures des méthodes à la sauce COM.<br />
Ainsi, une méthode :</p>
<p><code class="codecolorer text default"><span class="text">String^ ReadLine();</span></code></p>
<p>sera wrappée en </p>
<p><code class="codecolorer text default"><span class="text">HRESULT ReadLine(/*[out,retval]*/ BSTR);</span></code></p>
<p>Ce qui suggère l&rsquo;utilisation de la macro SUCCEEDED pour tester la bonne marche de la fonction.</p>
<p>Mais pouvons-nous encore simplifier et se passer de ce type de signature ? On aimerait pouvoir avoir une signature du genre :</p>
<p><code class="codecolorer text default"><span class="text">BSTR ReadLine();</span></code></p>
<p>Bref, conserver la signature de la méthode, aux types près &#8230;</p>
<p><span id="more-24"></span></p>
<p>Et bien c&rsquo;est possible, grâce à un attribut disponible dans le namespace System::Runtime::CompilerServices.</p>
<p>Notre classe managée ne change pas d&rsquo;écriture, mais l&rsquo;interface sera écrite ainsi :</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">using namespace System::Runtime::CompilerServices; <br />
&nbsp;<br />
namespace MonStreamReader &nbsp;<br />
{ <br />
&nbsp; public interface class IClassWrap <br />
&nbsp; { <br />
&nbsp; &nbsp; [MethodImpl(MethodImplOptions::PreserveSig)] <br />
&nbsp; &nbsp; void SetFile(String ^fileName); <br />
&nbsp; &nbsp; [MethodImpl(MethodImplOptions::PreserveSig)] <br />
&nbsp; &nbsp; bool Create(); <br />
&nbsp; &nbsp; [MethodImpl(MethodImplOptions::PreserveSig)] <br />
&nbsp; &nbsp; String^ ReadLine(); <br />
&nbsp; }; <br />
&nbsp;<br />
&nbsp; public ref class ClassWrap : IClassWrap <br />
&nbsp; { <br />
&nbsp; &nbsp; &nbsp;......... <br />
&nbsp; } <br />
}</div></div>
<p>L&rsquo;attribut <strong>PreserveSig</strong>, comme son nom le suggère un peu, permet de préserver la signature ; et au final de simplifier encore un brin le programme natif.</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">int _tmain(int argc, _TCHAR* argv[]) <br />
{ <br />
&nbsp; CoInitialize(NULL); <br />
&nbsp; MonStreamReader::IClassWrapPtr pClass(__uuidof(MonStreamReader::ClassWrap)); <br />
&nbsp; CComBSTR filePath = &quot;c:\\test.txt&quot;; <br />
&nbsp; pClass-&gt;SetFile(filePath); <br />
&nbsp; if (pClass-&gt;Create()) <br />
&nbsp; { <br />
&nbsp; &nbsp; CComBSTR line; <br />
&nbsp; &nbsp; line = pClass-&gt;ReadLine(); <br />
&nbsp; &nbsp; while (line) <br />
&nbsp; &nbsp; { <br />
&nbsp; &nbsp; &nbsp; _bstr_t line_(line); <br />
&nbsp; &nbsp; &nbsp; std::cout &lt;&lt; line_ &lt;&lt; std::endl; <br />
&nbsp; &nbsp; &nbsp; line = pClass-&gt;ReadLine(); <br />
&nbsp; &nbsp; } <br />
&nbsp; } <br />
&nbsp; return 0; <br />
}</div></div>
<p>Dingue ca, on dirait presque du C++/CLI :p, à part un ou deux BSTR qui trainent &#8230;</p>
<p>Un dernier petit truc : ne faites pas trop confiance à l&rsquo;intellisense, il se débrouille pas trop mal, mais suite à quelques compilations, enregistrements, &#8230; dès fois, il pert un peu le nord. Heureusement que nous savons exactement ce que nous voulons faire <img src="https://blog.developpez.com/nico-pyright/wp-includes/images/smilies/icon_smile.gif" alt=":)" class="wp-smiley" /></p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Wrapper de classes pour COM Interop, simplification et utilisation d&#8217;interfaces</title>
		<link>https://blog.developpez.com/nico-pyright/p3821/cc-win32/wrapper_de_classes_pour_com_interop_simp</link>
		<comments>https://blog.developpez.com/nico-pyright/p3821/cc-win32/wrapper_de_classes_pour_com_interop_simp#comments</comments>
		<pubDate>Thu, 21 Jun 2007 00:19:38 +0000</pubDate>
		<dc:creator><![CDATA[nico-pyright(c)]]></dc:creator>
				<category><![CDATA[C++ Interop]]></category>
		<category><![CDATA[C/C++ - Win32]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Si vous êtes allé au bout du précédent billet, je vous félicite. Je rappelle que le but est de pouvoir utiliser un objet .net depuis notre exe natif pur et de passer des paramètres à son constructeur via un wrapper CLI. Quand je re-regarde le code du billet, il me fait peur Tout ce code pour finalement si peu de choses&#8230; N&#8217;y aurait-il pas moyen de faire plus simple ? Forcément, si j&#8217;écris ca, c&#8217;est [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Si vous êtes allé au bout du précédent billet, je vous félicite. Je rappelle que le but est de pouvoir utiliser un objet .net depuis notre exe natif pur et de passer des paramètres à son constructeur via un wrapper CLI.<br />
Quand je re-regarde le code du billet, il me fait peur <img src="https://blog.developpez.com/nico-pyright/wp-includes/images/smilies/icon_smile.gif" alt=":)" class="wp-smiley" /> Tout ce code pour finalement si peu de choses&#8230;</p>
<p>N&rsquo;y aurait-il pas moyen de faire plus simple ?</p>
<p>Forcément, si j&rsquo;écris ca, c&rsquo;est qu&rsquo;il doit y avoir un moyen&#8230;<span id="more-23"></span></p>
<p>La solution est d&rsquo;utiliser la capacité de visual studio à incorporer les tlb grâce à #import et à le convertir en classes C++.</p>
<p>Nous transformons notre précédente classe managée qui wrappe de manière simpliste le StreamReader pour faire en sorte que la classe implémente une interface :</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">using namespace System; <br />
using namespace System::IO; <br />
&nbsp;<br />
namespace MonStreamReader &nbsp;<br />
{ <br />
&nbsp; public interface class IClassWrap <br />
&nbsp; { <br />
&nbsp; &nbsp; void SetFile(String ^fileName); <br />
&nbsp; &nbsp; bool Create(); <br />
&nbsp; &nbsp; String^ ReadLine(); <br />
&nbsp; }; <br />
&nbsp;<br />
&nbsp; public ref class ClassWrap : IClassWrap <br />
&nbsp; { <br />
&nbsp; private: &nbsp;<br />
&nbsp; &nbsp; String ^_fileName; <br />
&nbsp; &nbsp; StreamReader ^sr; <br />
&nbsp; protected: <br />
&nbsp; &nbsp; !ClassWrap() <br />
&nbsp; &nbsp; { <br />
&nbsp; &nbsp; &nbsp; if (sr) <br />
&nbsp; &nbsp; &nbsp; &nbsp; sr-&gt;Close(); <br />
&nbsp; &nbsp; } <br />
&nbsp; public: <br />
&nbsp; &nbsp; ClassWrap() {} <br />
&nbsp; &nbsp; ~ClassWrap() <br />
&nbsp; &nbsp; { <br />
&nbsp; &nbsp; &nbsp; this-&gt;!ClassWrap(); <br />
&nbsp; &nbsp; } <br />
&nbsp; &nbsp; virtual void SetFile(String ^fileName) <br />
&nbsp; &nbsp; { <br />
&nbsp; &nbsp; &nbsp; _fileName = fileName; <br />
&nbsp; &nbsp; } <br />
&nbsp; &nbsp; virtual bool Create() <br />
&nbsp; &nbsp; { <br />
&nbsp; &nbsp; &nbsp; if (!String::IsNullOrEmpty(_fileName)) <br />
&nbsp; &nbsp; &nbsp; { <br />
&nbsp; &nbsp; &nbsp; &nbsp; try <br />
&nbsp; &nbsp; &nbsp; &nbsp; { <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sr = gcnew StreamReader(_fileName); <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return true; <br />
&nbsp; &nbsp; &nbsp; &nbsp; } <br />
&nbsp; &nbsp; &nbsp; &nbsp; catch (Exception ^) <br />
&nbsp; &nbsp; &nbsp; &nbsp; { <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sr = nullptr; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return false; <br />
&nbsp; &nbsp; &nbsp; &nbsp; } <br />
&nbsp; &nbsp; &nbsp; } <br />
&nbsp; &nbsp; &nbsp; return false; <br />
&nbsp; &nbsp; } <br />
&nbsp; &nbsp; virtual String^ ReadLine() <br />
&nbsp; &nbsp; { <br />
&nbsp; &nbsp; &nbsp; if (sr) <br />
&nbsp; &nbsp; &nbsp; &nbsp; return sr-&gt;ReadLine(); <br />
&nbsp; &nbsp; &nbsp; return nullptr; <br />
&nbsp; &nbsp; } &nbsp;}; <br />
}</div></div>
<p>On génère le tlb, et on l&rsquo;importe dans notre programme natif. Visual C++ va générer des classes et notamment une qui nous interesse IClassWrapPtr. C&rsquo;est un smart pointer qui permet d&rsquo;accèder à l&rsquo;objet COM.</p>
<p>Il ne reste plus qu&rsquo;à utiliser ce smart pointer pour appeler directement les méthodes de notre classe. Notez que les fonctions ont été relookées à la mode COM. On récupère un HRESULT et le retour de fonction se fait par un paramètre en sortie [out].</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">#include &lt;atlsafe.h&gt; <br />
#include &lt;iostream&gt; <br />
&nbsp;<br />
#import &quot;..\debug\MonStreamReader.tlb&quot; raw_interfaces_only <br />
&nbsp;<br />
&nbsp;<br />
int _tmain(int argc, _TCHAR* argv[]) <br />
{ <br />
&nbsp; CoInitialize(NULL); <br />
&nbsp; MonStreamReader::IClassWrapPtr pClass(__uuidof(MonStreamReader::ClassWrap)); <br />
&nbsp; CComBSTR filePath = &quot;c:\\test.txt&quot;; <br />
&nbsp; if (SUCCEEDED(pClass-&gt;SetFile(filePath))) <br />
&nbsp; { <br />
&nbsp; &nbsp; unsigned char resultBool; <br />
&nbsp; &nbsp; if (SUCCEEDED(pClass-&gt;Create(&amp;resultBool))) <br />
&nbsp; &nbsp; { <br />
&nbsp; &nbsp; &nbsp; if (resultBool) <br />
&nbsp; &nbsp; &nbsp; { <br />
&nbsp; &nbsp; &nbsp; &nbsp; CComBSTR line; <br />
&nbsp; &nbsp; &nbsp; &nbsp; if (SUCCEEDED(pClass-&gt;ReadLine(&amp;line))) <br />
&nbsp; &nbsp; &nbsp; &nbsp; { <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; while (line) <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; _bstr_t line_(line); <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; std::cout &lt;&lt; line_ &lt;&lt; std::endl; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (FAILED(pClass-&gt;ReadLine(&amp;line))) <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } <br />
&nbsp; &nbsp; &nbsp; &nbsp; } <br />
&nbsp; &nbsp; &nbsp; } <br />
&nbsp; &nbsp; } <br />
&nbsp; } <br />
&nbsp; return 0; <br />
}</div></div>
<p>C&rsquo;est quand même plus digeste !!<br />
Notez l&rsquo;utilisation de CComBstr pour passer des chaines qui seront marshalées en String^.net. Par contre, mon retour booleen donne un unsigned char.<br />
Pour l&rsquo;affichage, j&rsquo;utilise également la classe _bstr_t qui dispose d&rsquo;une surcharge de char *.</p>
<p>Vous pouvez <a href="ftp://ftp-developpez.com/nico-pyright/blog/MonStreamReader.rar">télécharger le projet exemple</a>.</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
