<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://geeks.ms/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>.NET o no .NET, esa es la cuestión : interop, Visual Studio</title><link>http://geeks.ms/blogs/rfog/archive/tags/interop/Visual+Studio/default.aspx</link><description>Etiquetas: interop, Visual Studio</description><dc:language /><generator>CommunityServer 2008.5 SP1 (Build: 31106.3070)</generator><item><title>Viendo el código fuente de .NET con Visual Studio 2012</title><link>http://geeks.ms/blogs/rfog/archive/2012/09/15/viendo-el-c-243-digo-fuente-de-net-con-visual-studio-2012.aspx</link><pubDate>Sat, 15 Sep 2012 11:19:14 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:206758</guid><dc:creator>Rafael Ontivero</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/rfog/rsscomments.aspx?PostID=206758</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/rfog/commentapi.aspx?PostID=206758</wfw:comment><comments>http://geeks.ms/blogs/rfog/archive/2012/09/15/viendo-el-c-243-digo-fuente-de-net-con-visual-studio-2012.aspx#comments</comments><description>&lt;p&gt;Quien tenga una versión anterior de Visual Studio seguro que sabe que se puede navegar por las tripas de .NET y ver cómo Microsoft ha implementado todo el tema. Pues bien, más o menos a &lt;a href="http://blogs.msdn.com/b/dotnet/archive/2012/08/15/announcing-the-release-of-net-framework-4-5-rtm-product-and-source-code.aspx"&gt;mediados de agosto del corriente&lt;/a&gt; (2012) se anunció la disponibilidad del código fuente de .NET 4.5, lo que nos permite meternos en las tripas del Framework y, lo que es mucho más interesante, mirar cómo funciona todo lo nuevo relacionado con Windows 8.&lt;/p&gt;  &lt;p&gt;El artículo citado da un somero repaso a las novedades no específicas de la biblioteca, entre las que se pueden destacar el añadido de métodos asíncronos en conjunción con las clases de tareas, y que ahora el &lt;i&gt;jitter&lt;/i&gt; es capaz de optimizar el código para los procesadores multinúcleo. También se mejora el rendimiento de casi todo (como siempre dicen, lo que a veces no es cierto), y se potencia el acceso de .NET a nueva parte nativa de Windows 8 (o RT o Metro o como quieras llamarlo), que es código nativo escrito en C++ y C++/CX, permitiendo a este lenguaje acceder, también, a código escrito en otros lenguajes .NET gracias a su parte CX (que como ya he dicho varias veces, es nativa).&lt;/p&gt;  &lt;p&gt;Como en otras versiones, el código fuente está disponible para &lt;a href="http://referencesource.microsoft.com/netframework.aspx"&gt;descarga directa&lt;/a&gt;, o para ser visto desde nuestro propio código, y también como símbolos de depuración.&lt;/p&gt;  &lt;p&gt;La captura de abajo nos muestra una aplicación Metro por defecto, detenida en un punto de interrupción, tal y como se ve en mi Visual Studio 2012 sin cambiar la configuración por defecto:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rfog/clip_5F00_image002_5F00_2B0EE603.jpg"&gt;&lt;img title="clip_image002" style="border-top:0px;border-right:0px;background-image:none;border-bottom:0px;padding-top:0px;padding-left:0px;margin:0px;border-left:0px;display:inline;padding-right:0px;" border="0" alt="clip_image002" src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rfog/clip_5F00_image002_5F00_thumb_5F00_084DAE46.jpg" width="244" height="195" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Fijaos en que la ventana de &lt;i&gt;Call Stack&lt;/i&gt; estgá prácticamente vacía, y si hacemos &lt;i&gt;Step Into&lt;/i&gt; simplemente saltamos a la siguiente línea de nuestro código fuente.&lt;/p&gt;  &lt;p&gt;Vamos a habilitar la posibilidad de meternos dentro del código de Microsoft.&lt;/p&gt;  &lt;p&gt;Nos vamos a TOOLS -&amp;gt; PROPERTIES, abrimos la pestaña lateral de &lt;i&gt;Debugging&lt;/i&gt;, y cambiamos las siguientes opciones:&lt;/p&gt;  &lt;p&gt;· Marcar &lt;i&gt;Enable Just My Code&lt;/i&gt;&lt;/p&gt;  &lt;p&gt;· Marcar &lt;i&gt;Enable .NET Framework source stepping&lt;/i&gt;&lt;/p&gt;  &lt;p&gt;· Desmarcar &lt;i&gt;Step over porperties and operators (Managed only)&lt;/i&gt;&lt;/p&gt;  &lt;p&gt;· Marcar &lt;i&gt;Enable source server support&lt;/i&gt;&lt;/p&gt;  &lt;p&gt;· Desmarcar &lt;i&gt;Require source files to exactly match the original version&lt;/i&gt;.&lt;/p&gt;  &lt;p&gt;Dejadlo todo más o menos como en la imagen:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rfog/clip_5F00_image003_5F00_0A1E040D.png"&gt;&lt;img title="clip_image003" style="border-top:0px;border-right:0px;background-image:none;border-bottom:0px;padding-top:0px;padding-left:0px;margin:0px;border-left:0px;display:inline;padding-right:0px;" border="0" alt="clip_image003" src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rfog/clip_5F00_image003_5F00_thumb_5F00_675CCC4F.png" width="244" height="144" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Ahora, en la pestaña de &lt;i&gt;Symbols&lt;/i&gt;, hay que añadir una nueva dirección de descarga de los mismos: &lt;a href="http://referencesource.microsoft.com/symbols"&gt;http://referencesource.microsoft.com/symbols&lt;/a&gt;. Como en la capura.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rfog/clip_5F00_image004_5F00_0BF0EA85.png"&gt;&lt;img title="clip_image004" style="border-top:0px;border-right:0px;background-image:none;border-bottom:0px;padding-top:0px;padding-left:0px;margin:0px;border-left:0px;display:inline;padding-right:0px;" border="0" alt="clip_image004" src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rfog/clip_5F00_image004_5F00_thumb_5F00_1DD00F03.png" width="244" height="144" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Finalmente, cuando le deis a OK el IDE se quedará bajando ficheros. Hay que esperar a que termine, y dependiendo de lo rápida que sea tu conexión, tendrás que esperar bastante tiempo.&lt;/p&gt;  &lt;p&gt;Con esta configuración, cada vez que se necesite algo, el IDE irá a los servidores de Microsoft, por lo que la carga y depuración de vuestro programa podría ser muy lenta a veces… por lo que se pueden bajar todos los símbolos de una tacada e instalarlos de forma local, apuntando la URL anterior a done los hayamos instalado. Podéis bajarlos de &lt;a href="http://referencesource.microsoft.com/netframework.aspx"&gt;aquí&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;La siguiente captura muestra algo de las tripas de Metro:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rfog/clip_5F00_image006_5F00_2D0677D0.jpg"&gt;&lt;img title="clip_image006" style="border-top:0px;border-right:0px;background-image:none;border-bottom:0px;padding-top:0px;padding-left:0px;border-left:0px;display:inline;padding-right:0px;" border="0" alt="clip_image006" src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rfog/clip_5F00_image006_5F00_thumb_5F00_25E9CC09.jpg" width="244" height="195" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Vale. Ahora el tío de la rebaja. ¿Habéis intentado profundizar en el código fuente, en métodos como el &lt;i&gt;Activate()&lt;/i&gt; de la primera captura? No entra, ¿verdad? No muestra código fuente, sino que simplemente salta sobre la llamada.&lt;/p&gt;  &lt;p&gt;Un gallinfante a quien adivine por qué es. &lt;/p&gt;  &lt;p&gt;Vale: es código nativo. Es decir, la parte Metro del .NET Framework no es código manejado, sino nativo. Es decir, está escrita en C++/CX, en donde la parte CX actúa como &lt;i&gt;Sugar Syntax&lt;/i&gt; de todo el perifostio COM y COM+ que finalmente es .NET&lt;/p&gt;  &lt;p&gt;Y todavía me atrevería a añadir algo más. Metro esconde en la manga algunos trucos de desarrollo que a MS no le interesa que se sepan, y ya visteis &lt;a href="http://geeks.ms/blogs/rfog/archive/2012/06/05/ingenier-237-a-inversa-de-una-aplicaci-243-n-metro-m-225-s-f-225-cil-que-nunca.aspx"&gt;lo fácil que es hacer ingeniería inversa de una aplicación .NET&lt;/a&gt;. Si toda esa parte hubiera estado hecha con .NET, sería facilísimo meterle mano.&lt;/p&gt;  &lt;p&gt;¡Y qué cojones, donde esté C++ que se quite cualquier lenguajucho de mala muerte! ;-)&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=206758" width="1" height="1"&gt;</description><category domain="http://geeks.ms/blogs/rfog/archive/tags/Sistemas+Operativos/default.aspx">Sistemas Operativos</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/Visual+Studio/default.aspx">Visual Studio</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/interop/default.aspx">interop</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/lenguajes/default.aspx">lenguajes</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/Interoperabilidad/default.aspx">Interoperabilidad</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/C_2B002B002F00_CX/default.aspx">C++/CX</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/Windows+8/default.aspx">Windows 8</category></item><item><title>¿Qué es C++ y qué es C++/CLI?</title><link>http://geeks.ms/blogs/rfog/archive/2009/06/15/191-qu-233-es-c-y-qu-233-es-c-cli.aspx</link><pubDate>Mon, 15 Jun 2009 18:26:01 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:150535</guid><dc:creator>Rafael Ontivero</dc:creator><slash:comments>7</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/rfog/rsscomments.aspx?PostID=150535</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/rfog/commentapi.aspx?PostID=150535</wfw:comment><comments>http://geeks.ms/blogs/rfog/archive/2009/06/15/191-qu-233-es-c-y-qu-233-es-c-cli.aspx#comments</comments><description>&lt;p align="justify"&gt;&lt;b&gt;&lt;u&gt;Introducción&lt;/u&gt;&lt;/b&gt;&lt;/p&gt;  &lt;p align="justify"&gt;Suele aparecer con cierta frecuencia en los foros de ayuda cierta confusión entre C++ y C++/CLI. Hay quien pregunta algo de C++ siendo C++/CLI y viceversa, o quien intenta aplicar algo de C++/CLI a C++ (y también al revés), o simplemente se ve completamente ofuscado con el tema. En esta entrada vamos a intentar poner un poco de orden en todo esto.&lt;/p&gt;  &lt;p align="justify"&gt;&lt;b&gt;&lt;u&gt;C++ no es C++/CLI&lt;/u&gt;&lt;/b&gt;&lt;/p&gt;  &lt;p align="justify"&gt;C++ es el lenguaje de toda la vida, inventando por Stroustrup y que, pese al deseo de muchos, está más vivo que nunca y sigue creciendo en funcionalidades y potencia, como es el hecho de que el próximo estándar va a añadir cosas muy interesantes que veremos por aquí. Si no pasa nada, antes de fin de año estará aprobado, se llamará C++09 y sustituirá a C++03 (No, no os penséis que hay 6 versiones entre uno y otro, no, es que el estándar se llama con el año en que se aprobó –si, ya sé que no es lo óptimo pero es así).&lt;/p&gt;  &lt;p align="justify"&gt;En C++ tenemos punteros, referencias, clases, herencia, polimorfismo y todo lo clásico del lenguaje, y los últimos compiladores de Microsoft lo implementan muy bien. Es decir, con Visual C++ (la versión que sea), se puede seguir programando como hasta ahora, con MFC, con Win32 o con cualquier otra biblioteca existente (QT, wxWidgets, y un largo etcétera).&lt;/p&gt;  &lt;p align="justify"&gt;Luego tenemos la plataforma .NET, en la que C++ no puede entrar directamente ya que hay cosas que .NET no soporta, entre las que caben destacar los punteros y la herencia múltiple. No vamos a entrar en detalles de por qué eso no funciona, sino que vamos a aceptarlo como dogma (quizás en algún momento futuro me dé por explicarlo, aunque tampoco es un tema difícil en exceso).&lt;/p&gt;  &lt;p align="justify"&gt;Por lo tanto Microsoft creó un nuevo lenguaje que llamó C++/CLI&lt;a name="_ftnref1_4631"&gt;[1]&lt;/a&gt;, es decir, el C++ del CLI. Si bien en su momento fue diseñado para que fuera un lenguaje de primera clase (otra forma de decir que debía soportar &lt;b&gt;todo&lt;/b&gt; el conjunto de .NET), con la llegada de la versión 3 del Framework C++/CLI se quedó como una herramienta avanzada de interoperabilidad entre .NET y Win32 (luego veremos más sobre esto).&lt;/p&gt;  &lt;p align="justify"&gt;Existen dos formas para acercarnos a las diferencias entre C++ y C++/CLI, o más bien se trata de dos maneras de explicar los mismos conceptos. Yo al menos no tengo clara cuál es la versión formal, si bien me aboco por la primera. Veamos en detalle estas das aproximaciones.&lt;/p&gt;  &lt;p align="justify"&gt;&lt;b&gt;&lt;u&gt;PRIMERA APROXIMACIÓN: C++ es un subconjunto de C++CLI&lt;/u&gt;&lt;/b&gt;&lt;/p&gt;  &lt;p align="justify"&gt;C++/CLI &lt;i&gt;incluye&lt;/i&gt; a C++. Es decir, todo lo que se puede hacer en C++ también se puede hacer en C++/CLI, y más. Si nosotros cogemos un código fuente escrito en C++ y lo compilamos como C++/CLI obtendremos un programa completamente funcional igual que lo era compilado en C++. No vale intentar llamar a una DLL nativa como si fuera nuestro programa, ni a un fichero objeto ya compilado (no me refiero a un &lt;i&gt;objeto&lt;/i&gt;, sino a un fichero .obj), debemos partir del código fuente, todo el código fuente.&lt;/p&gt;  &lt;p align="justify"&gt;De este modo, hemos convertido un programa C++ en otro C++/CLI que necesita el .NET Framework para funcionar pero que simplemente continua siendo, exactamente, el mismo que antes y con el mismo código fuente.&lt;/p&gt;  &lt;p align="justify"&gt;Y entonces podemos añadir código que use cosas del .NET, con ciertas limitaciones que veremos luego, pero lo que sí podemos es utilizar los nuevos conceptos de .NET, como referencias manejadas, liberación automática de memoria, genéricos y demás zarandajas.&lt;/p&gt;  &lt;p align="justify"&gt;Por lo tanto, está claro que C++ es un subconjunto de C++/CLI desde este punto de vista.&lt;/p&gt;  &lt;p align="justify"&gt;&lt;b&gt;&lt;u&gt;SEGUNDA APROXIMACIÓN: Son lenguajes diferentes que funcionan lado a lado&lt;/u&gt;&lt;/b&gt;&lt;/p&gt;  &lt;p align="justify"&gt;Aquí C++ tiene una parte de su sintaxis compartida con C++/CLI de igual modo que el primero la tiene con C. No obstante, son dos lenguajes completamente diferentes que no sólo pueden interactuar entre sí (como C y C++), sino que incluso pueden escribirse en un mismo código fuente, de manera que unas sentencias estarán en C++ y otras en C++/CLI.&lt;/p&gt;  &lt;p align="justify"&gt;A primera vista puede parecer extraño, pero lo cierto es que se trata de una aproximación también correcta (y lo demostraremos). &lt;/p&gt;  &lt;p align="justify"&gt;Si bien podemos compilar un programa existente como .NET, ese código no usa nada de .NET, y el código que creemos para usar .NET no se puede utilizar con el antiguo, no al menos de forma directa: no podemos tener una referencia manejada a un objeto nativo, ni un puntero nativo a una referencia manejada, no podemos obtener la dirección de un objeto manejado, y muchas otras limitaciones más.&lt;/p&gt;  &lt;p align="justify"&gt;Sin embargo, sí que hay otras cosas que podemos compartir de forma indistinta: muchos de los tipos nativos, podemos alojar un puntero nativo en una clase manejada (al revés también, pero con ciertas complicaciones adicionales), y podemos interactuar con código nativo de forma mucho más sencilla que con otros lenguajes.&lt;/p&gt;  &lt;p align="justify"&gt;&lt;b&gt;&lt;u&gt;RESUMIENDO, que es gerundio&lt;/u&gt;&lt;/b&gt;&lt;/p&gt;  &lt;p align="justify"&gt;Antes de entrar en otras profundidades, conviene hacer un breve resumen de lo que estamos tratando.&lt;/p&gt;  &lt;p align="justify"&gt;Hemos visto que Microsoft tiene dos lenguajes C++: el tradicional y el .NET, llamado C++/CLI. Con el primero ellos podemos construir programas tradicionales (MFC, QT, Win32, etc.). Con el segundo desarrollamos aplicaciones para .NET.&lt;/p&gt;  &lt;p align="justify"&gt;Por otro lado, podemos mezclarlos, o usarlos de forma combinada para crear aplicaciones mixtas que usen partes en Win32 o nativas y partes en .NET o manejadas.&lt;/p&gt;  &lt;p align="justify"&gt;No obstante, son lenguajes diferentes que comparten bastante sintaxis.&lt;/p&gt;  &lt;p align="justify"&gt;&lt;b&gt;&lt;u&gt;Rizando el rizo&lt;/u&gt;&lt;/b&gt;&lt;/p&gt;  &lt;p align="justify"&gt;Supongamos el siguiente programa, creado a partir del asistente para &amp;quot;Consola CLR&amp;quot;, que es como MS llama a un programa C++/CLI en modo consola.&lt;/p&gt;  &lt;pre&gt;#&lt;span style="color:#0000ff;"&gt;include&lt;/span&gt; &lt;span style="color:#b22222;"&gt;&amp;quot;stdafx.h&amp;quot;&lt;/span&gt;

#&lt;span style="color:#0000ff;"&gt;include&lt;/span&gt; &amp;lt;stdio.h&amp;gt;

&lt;span style="color:#0000ff;"&gt;using&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;namespace&lt;/span&gt; System;

&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;main&lt;/span&gt;(array&amp;lt;System::String ^&amp;gt; ^args)
{
    printf(&lt;span style="color:#b22222;"&gt;&amp;quot;Hello World&amp;quot;&lt;/span&gt;);
    Console::WriteLine(&lt;span style="color:#b22222;"&gt;&amp;quot;Hello World&amp;quot;&lt;/span&gt;);
    &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; 0;
}&lt;/pre&gt;

&lt;p align="justify"&gt;Si nos fijamos atentamente, es una mezcla de código nativo (la inclusión de &lt;i&gt;stdio.h&lt;/i&gt; y la línea que contiene &lt;i&gt;printf&lt;/i&gt;) y código puramente .NET, y si lo ejecutamos veremos cómo se imprimen ambas líneas por la consola.&lt;/p&gt;

&lt;p align="justify"&gt;Por otro lado, podemos elegir entre tres modos de generar un programa en C++/CLI: la opción por defecto es &amp;quot;/clr&amp;quot;, aparte de &amp;quot;/clr:pure&amp;quot; y &amp;quot;/clr:safe&amp;quot;. ¿En qué afectan a nuestro modelo? En bastantes cosas. La imagen siguiente nos localiza, dentro de las opciones del proyecto, el lugar en dónde cambiarlo:&lt;/p&gt;

&lt;p align="justify"&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rfog/clip_5F00_image002_5F00_13670344.jpg"&gt;&lt;img style="border-bottom:0px;border-left:0px;display:inline;border-top:0px;border-right:0px;" title="clip_image002" border="0" alt="clip_image002" src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rfog/clip_5F00_image002_5F00_thumb_5F00_2392CB3D.jpg" width="572" height="398" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p align="justify"&gt;La primera de ellas es que la opción &amp;quot;/clr:safe&amp;quot; no nos permite compilar código mixto; es decir, si intentamos compilar el programa de arriba con esa opción obtendremos una muy larga lista de errores en relación a la inclusión de &lt;i&gt;stdio.h&lt;/i&gt; y del &lt;i&gt;printf&lt;/i&gt;. Si quitamos esas dos líneas y compilamos con dicha opción nuestro programa, se ejecutará sin problemas, y si lo miramos por ejemplo con el .NET Reflector veremos que es idéntico (o casi) a cualquier otro programa equivalente escrito en, por ejemplo, C#.&lt;/p&gt;

&lt;p align="justify"&gt;&amp;quot;/clr:pure&amp;quot; nos dice que nuestro programa, aparte de acceder a código manejado, también puede tener código nativo &lt;i&gt;compilado como código manejado&lt;/i&gt;. Y finalmente la opción por defecto nos permite, aparte de lo anterior, acceder a módulos completamente compilados como código nativo y a compilar la parte nativa como tal.&lt;/p&gt;

&lt;p align="justify"&gt;Por ejemplo, si compilamos nuestro ejemplo con cualquiera de las dos opciones reseñadas, obtenemos el siguiente código generado por el .NET Reflector:&lt;/p&gt;

&lt;pre&gt;&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;main&lt;/span&gt;(&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;argc&lt;/span&gt;, &lt;span style="color:#0000ff;"&gt;char&lt;/span&gt; modopt(IsSignUnspecifiedByte^)** &lt;span style="color:#0000ff;"&gt;argv&lt;/span&gt;)
{
    ::printf(&amp;amp;::?A0x67b7b245.unnamed-global-0);
    Console::WriteLine(&lt;span style="color:#b22222;"&gt;&amp;quot;Hello World&amp;quot;&lt;/span&gt;);
    &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; 0;
}&lt;/pre&gt;

&lt;p align="justify"&gt;Vemos cómo hacemos una llamada a la función printf, que es nativa, con una cadena también nativa y luego hacemos una llamada a &lt;i&gt;WriteLine&lt;/i&gt; con una nueva cadena, esta vez todo código manejado. &lt;/p&gt;

&lt;p align="justify"&gt;Una primera aproximación nos dice que C++ es un subconjunto de C++/CLI ya que la llamada a &lt;i&gt;printf&lt;/i&gt; se realiza desde código manejado, y el parámetro es la dirección de un miembro de una estructura global, o eso parece). Estamos en la primera aproximación.&lt;i&gt;&lt;/i&gt;&lt;/p&gt;

&lt;p align="justify"&gt;&lt;b&gt;&lt;u&gt;Segunda vuelta al rizo&lt;/u&gt;&lt;/b&gt;&lt;/p&gt;

&lt;p align="justify"&gt;Veamos ahora el siguiente código:&lt;/p&gt;

&lt;pre&gt;#&lt;span style="color:#0000ff;"&gt;include&lt;/span&gt; &lt;span style="color:#b22222;"&gt;&amp;quot;stdafx.h&amp;quot;&lt;/span&gt;
#&lt;span style="color:#0000ff;"&gt;include&lt;/span&gt; &amp;lt;stdio.h&amp;gt;

&lt;span style="color:#0000ff;"&gt;using&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;namespace&lt;/span&gt; System;

&lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; printk(&lt;span style="color:#0000ff;"&gt;const&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;char&lt;/span&gt; *p)
{
    &lt;span style="color:#0000ff;"&gt;while&lt;/span&gt;(*p)
    putchar(*p++);
}

&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;main&lt;/span&gt;(&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;argc&lt;/span&gt;,&lt;span style="color:#0000ff;"&gt;char&lt;/span&gt; **&lt;span style="color:#0000ff;"&gt;argv&lt;/span&gt;)
{
    printk(&lt;span style="color:#b22222;"&gt;&amp;quot;Hello World&amp;quot;&lt;/span&gt;);
    Console::WriteLine(&lt;span style="color:#b22222;"&gt;&amp;quot;Hello World&amp;quot;&lt;/span&gt;);
    &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; 0;
}&lt;/pre&gt;

&lt;p align="justify"&gt;Hemos cambiado poco, pero lo suficiente para ver ciertas diferencias en el código compilado resultante. Hemos añadido una función nativa que recibe un puntero a una cadena y la pone en consola. &lt;/p&gt;

&lt;p align="justify"&gt;¿Qué se imagina el lector que pasará al compilar esto tanto con &amp;quot;/clr&amp;quot; como con &amp;quot;/clr:pure&amp;quot; (recordemos que &amp;quot;/clr:safe&amp;quot; no puede contener código nativo de ningún tipo)? ¿Qué pasará con la función &lt;i&gt;printk&lt;/i&gt;?&lt;/p&gt;

&lt;p align="justify"&gt;Veámoslo, pero esta vez con el ILDasm:&lt;/p&gt;

&lt;p align="justify"&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rfog/clip_5F00_image004_5F00_21E1FF69.jpg"&gt;&lt;img style="border-bottom:0px;border-left:0px;display:inline;border-top:0px;border-right:0px;" title="clip_image004" border="0" alt="clip_image004" src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rfog/clip_5F00_image004_5F00_thumb_5F00_20313395.jpg" width="572" height="361" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p align="justify"&gt;Da igual que lo compilemos con cualquiera de las dos opciones, de nuevo una función nativa ha sido compilada como manejada, estamos, otra vez, en el primer caso (y recordemos que .NET, junto a C#, permite punteros, algo no muy tenido en cuenta a veces).&lt;/p&gt;

&lt;p align="justify"&gt;&lt;b&gt;&lt;u&gt;El tercer rizo (y punto final)&lt;/u&gt;&lt;/b&gt;&lt;/p&gt;

&lt;p align="justify"&gt;Bueno, ya sólo nos queda un nuevo ejemplo de código:&lt;/p&gt;

&lt;pre&gt;#&lt;span style="color:#0000ff;"&gt;include&lt;/span&gt; &lt;span style="color:#b22222;"&gt;&amp;quot;stdafx.h&amp;quot;&lt;/span&gt;
#&lt;span style="color:#0000ff;"&gt;include&lt;/span&gt; &amp;lt;stdio.h&amp;gt;

&lt;span style="color:#0000ff;"&gt;using&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;namespace&lt;/span&gt; System;

#&lt;span style="color:#0000ff;"&gt;pragma&lt;/span&gt; unmanaged
&lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; printk(&lt;span style="color:#0000ff;"&gt;const&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;char&lt;/span&gt; *p)
{
    &lt;span style="color:#0000ff;"&gt;while&lt;/span&gt;(*p)
    putchar(*p++);
}
#&lt;span style="color:#0000ff;"&gt;pragma&lt;/span&gt; managed

&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;main&lt;/span&gt;(&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;argc&lt;/span&gt;,&lt;span style="color:#0000ff;"&gt;char&lt;/span&gt; **&lt;span style="color:#0000ff;"&gt;argv&lt;/span&gt;)
{
    printk(&lt;span style="color:#b22222;"&gt;&amp;quot;Hello World&amp;quot;&lt;/span&gt;);
    Console::WriteLine(&lt;span style="color:#b22222;"&gt;&amp;quot;Hello World&amp;quot;&lt;/span&gt;);
    &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; 0;
}&lt;/pre&gt;

&lt;p align="justify"&gt;Hemos colocado nuestra función nativa bajo las directivas del preprocesador indicadas. Si ahora intentamos compilar este programa con la opción &amp;quot;/clr:pure&amp;quot;, nos saltará un error diciéndonos que no podemos compilar la función &lt;i&gt;printk&lt;/i&gt; como nativa bajo este modelo. &lt;/p&gt;

&lt;p align="justify"&gt;No obstante, si lo hacemos con &amp;quot;/clr&amp;quot;, obtendremos el siguiente código para la función &lt;i&gt;printk&lt;/i&gt;:&lt;/p&gt;

&lt;p align="justify"&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rfog/clip_5F00_image006_5F00_65698ABE.jpg"&gt;&lt;img style="border-bottom:0px;border-left:0px;display:inline;border-top:0px;border-right:0px;" title="clip_image006" border="0" alt="clip_image006" src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rfog/clip_5F00_image006_5F00_thumb_5F00_18C54E1B.jpg" width="571" height="361" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p align="justify"&gt;¡Ondia! No está, no hay nada… Realmente está ahí, pero al ser código nativo, ni el ILDasm ni el Reflector son capaces de verlo. Ahora nos hemos acercado un poco más a la segunda aproximación, en la que estamos viendo cómo C++ va por un lado y C++/CLI por el otro. &lt;/p&gt;

&lt;p align="justify"&gt;Sí, ya sé que es una forma un poco retorcida de verlo, pero sigamos…&lt;/p&gt;

&lt;p align="justify"&gt;Podríamos haberlo complicado un poco, compilando dos módulos independientes, uno con las opciones para C++/CLI y otro sin ellas, y haber hecho la llamada del manejado al nativo, pero ¡eso es exactamente lo que ocurría cuando hacíamos la llamada a &lt;i&gt;printf&lt;/i&gt;!&lt;/p&gt;

&lt;p align="justify"&gt;O a cualquier otra función de Win32 o de una biblioteca de C++ nativa. Por tanto, la segunda aproximación también es completamente cierta. Alguien podría objetar que “eso pertenece a una DLL”, pero podemos compilar nuestro código con enlace estático al &lt;em&gt;runtime&lt;/em&gt; de C y tendríamos el mismo caso: ejecutando código nativo y manejado desde un mismo ejecutable.&lt;/p&gt;

&lt;div align="justify"&gt;
  &lt;hr align="left" /&gt;&lt;/div&gt;

&lt;p align="justify"&gt;&lt;a name="_ftn1_4631"&gt;[1]&lt;/a&gt; Olvidémonos por completo de las &lt;i&gt;managed extensions&lt;/i&gt;, haremos como si no existieran ni hubieran existido nunca jamás de los jamases J.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=150535" width="1" height="1"&gt;</description><category domain="http://geeks.ms/blogs/rfog/archive/tags/c_2B002B002F00_cli/default.aspx">c++/cli</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/c_2B002B00_/default.aspx">c++</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/windows/default.aspx">windows</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/Visual+Studio/default.aspx">Visual Studio</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/interop/default.aspx">interop</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/lenguajes/default.aspx">lenguajes</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/Win32/default.aspx">Win32</category></item><item><title>La estructura intraducible, I (de Interop y otras yerbas)</title><link>http://geeks.ms/blogs/rfog/archive/2008/12/19/la-estructura-intraducible-i-de-interop-y-otras-yerbas.aspx</link><pubDate>Fri, 19 Dec 2008 19:23:45 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:132200</guid><dc:creator>Rafael Ontivero</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/rfog/rsscomments.aspx?PostID=132200</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/rfog/commentapi.aspx?PostID=132200</wfw:comment><comments>http://geeks.ms/blogs/rfog/archive/2008/12/19/la-estructura-intraducible-i-de-interop-y-otras-yerbas.aspx#comments</comments><description>&lt;p&gt;A veces resulta curioso cómo algo tan sencillo como mapear una estructura de C en .NET se puede convertir en un algo muy cercano a una pesadilla dependiendo del lenguaje que hayamos elegido para realizarlo. Partamos de la siguiente estructura de C:&lt;/p&gt;  &lt;pre&gt;typedef struct
{
    BYTE byOut[4]; // Outputs [0..3]
    BYTE byAux; // Aux output
} usbOutput;&lt;/pre&gt;

&lt;p&gt;A simple vista es algo muy elemental: un array de cuatro bytes y uno más después. Esto en una máquina Intel en realidad termina ocupando 8 bytes, 4 para el primer elemento y otros cuatro para el segundo si no se cambia la alineación.&lt;/p&gt;

&lt;p&gt;La traducción a C# requiere de ciertos trucos un tanto oscuros y no muy bien documentados:&lt;/p&gt;

&lt;pre&gt;[StructLayoutAttribute(LayoutKind.Sequential)]
public struct usbOutput
{
    [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 4)]
    public byte[] byOut;
    public byte byAux;
}&lt;/pre&gt;

&lt;p&gt;Todo el secreto está en la declaración de los atributos que preceden al array. Básicamente le estamos diciendo al runtime que lo que viene a continuación es un array embebido directamente y no un array normal; es decir, que en lugar de guardar un puntero en la estructura y coloque el array en otro lugar, lo que está haciendo es colocar el array de cuatro elementos directamente en la estructura.&lt;/p&gt;

&lt;p&gt;El autor no sabe si esa construcción funciona o no porque no lo ha probado, pero supone que debe hacerlo ya que si no difícilmente se iba a poder trabajar con Win32 desde C#.&lt;/p&gt;

&lt;p&gt;Pero resulta que uno está haciendo el ensamblado en C++/CLI para aprovechar las facilidades del código mixto, por lo que piensa que la traducción directa servirá:&lt;/p&gt;

&lt;pre&gt;[StructLayout(LayoutKind::Sequential)]
public value struct usbOutput
{
    [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 4)]
    Array&amp;lt;byte&amp;gt;^ byOut;
    byte byAux;
};&lt;/pre&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Pero tras las primeras pruebas descubre que no, que .NET te ignora olímpicamente y el array &lt;i&gt;byOut&lt;/i&gt; se queda como un puntero en la estructura, con el consiguiente desbarajuste cuando dicha estructura es bloqueada (mediante un &lt;i&gt;pin_ptr&lt;/i&gt;) y pasada a la función nativa. Con la experiencia del autor, en general o bien se te cuelga el IDE o bien el aplicativo empieza a hacer cosas bastante extrañas…&lt;/p&gt;

&lt;p&gt;Tras recorrerse Internet completo, de hecho el autor llegó hasta &lt;a href="http://www.shibumi.org/eoti.htm"&gt;aquí&lt;/a&gt;, no descubre nada que le sea útil excepto una construcción de Nishant Sivakumar que no le funciona bien. Pero como el autor de esta entrada tiene el libro de Nish, busca el original y descubre que la versión encontrada en Internet no funciona, pero la del libro sí lo hace, pero funciona sólo en C++/CLI, ya que si se llama a &lt;i&gt;byIn&lt;/i&gt; desde C#, el compilador falla debido a que la sobrecarga de operadores es mucho más versátil en C++ y C++/CLI que en C# y éste no sabe cómo actuar.&lt;/p&gt;

&lt;p&gt;La solución de Nish se puede encontrar en la página 185 de su libro titulado &lt;i&gt;&lt;a href="http://www.manning.com/sivakumar/"&gt;C++/CLI in Action&lt;/a&gt;&lt;/i&gt;, que recomiendo encarecidamente a todo aquel que quiera aprender este lenguaje. &lt;/p&gt;

&lt;p&gt;Mi solución parte de la de Nish con una ligera modificación, que es la de sustituir la sobrecarga del operador de acceso indexado, [], por el indexador por defecto.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;&lt;u&gt;La solución&lt;/u&gt;&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;La potencia expresiva de C++ es prácticamente infinita, ya que si existe alguna construcción en cualquier otro lenguaje que no exista en C++, resulta poco menos que seguro que se pueda simular y casi integrar en el lenguaje a través una biblioteca que simule el tipo o el constructo necesario, y eso es lo que aquí hemos hecho.&lt;/p&gt;

&lt;p&gt;Necesitamos &lt;i&gt;algo&lt;/i&gt; que nos permita insertar una secuencia repetida de un mismo elemento y que tenga semántica de array… Pues nada, elemental, querido Watson:&lt;/p&gt;

&lt;pre&gt;template&amp;lt;typename T,int size&amp;gt;
[StructLayout(LayoutKind::Sequential,Size=sizeof(T)*size)]
public value class FixedSizeArray
{
    T FixedElementField;
    public:
    property T default[int]
    {
        T get(int i)
        {
            return *(&amp;amp;FixedElementField+i);
        }
        void set(int i,T t)
        {
            *(&amp;amp;FixedElementField+i)=t;
        }
    }
};&lt;/pre&gt;

&lt;p&gt;Creamos un nuevo tipo que recibe un tipo llamado T y un entero que va a indicar el tamaño estático del array. Luego le decimos a .NET que nuestra clase es una estructura secuencial y que su tamaño es de tantas veces como elementos a repetir en relación al tipo base.&lt;/p&gt;

&lt;p&gt;Y declaramos el tipo en cuestión, que hemos llamado &lt;i&gt;FixedSizeArray&lt;/i&gt; y que contiene un elemento del tipo T. Asimismo posee un indexador por defecto que recibirá un entero que será el índice del elemento a leer o escribir. Lo único que le falta al ejemplo es controlar el tamaño del índice, pero como en el caso del autor es algo interno a él mismo, lo obvia.&lt;/p&gt;

&lt;p&gt;La línea más curiosa de todas es el acceso al elemento interno:&lt;/p&gt;

&lt;p&gt;*(&amp;amp;FixedElementField+i)&lt;/p&gt;

&lt;p&gt;Expresándolo paso a paso, en primer lugar obtenemos la dirección de memoria de &lt;i&gt;FixedElementField&lt;/i&gt; a través del operador &amp;amp;. A esa dirección añadimos el índice como si de un puntero de C++ se tratara, y luego desreferenciamos para obtener (o asignar) el valor.&lt;/p&gt;

&lt;p&gt;A primera vista no debería funcionar, pero sí que lo hace ya que debemos tener conocimiento de cómo C++ y C++/CLI (y en general casi cualquier lenguaje orientado a objetos funciona). Cuando uno crea un objeto de una clase, sólo está creando el bloque de datos del mismo, ya que la clase ha sido traducida a una lista de funciones más o menos globales que residen en el segmento de código, y cuando se invoca un método cualquiera, realmente estamos haciendo una llamada de función global pasando en primer lugar un puntero a la dirección donde están los datos…&lt;/p&gt;

&lt;p&gt;El uso de esta construcción es bien sencilla:&lt;/p&gt;

&lt;pre&gt;[StructLayout(LayoutKind::Sequential)]
public value struct usbOutput
{
    FixedSizeArray&amp;lt;byte,4&amp;gt;byOut;
    byte byAux;
};&lt;/pre&gt;

&lt;p&gt;Simplemente indicamos un objeto del tipo &lt;i&gt;FixedSizeArray&lt;/i&gt; del tipo y tamaños adecuado. Y el acceso desde, por ejemplo, C#, todavía lo es más:&lt;/p&gt;

&lt;pre&gt;usbInput input=new usbInput();
input. byOut[2]=55;
Console.WriteLine(input. byOut[2]);
GetInputs(ref input);
//etc.&lt;/pre&gt;

&lt;p&gt;La única limitación de esta construcción es que sólo permite simular arrays de una dimensión. En una próxima entrada pondré cómo hacerlo para elementos de varias.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=132200" width="1" height="1"&gt;</description><category domain="http://geeks.ms/blogs/rfog/archive/tags/c_2B002B002F00_cli/default.aspx">c++/cli</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/c_2B002B00_/default.aspx">c++</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/Visual+Studio/default.aspx">Visual Studio</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/interop/default.aspx">interop</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/tips/default.aspx">tips</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/Win32/default.aspx">Win32</category></item></channel></rss>