<?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 : Win32</title><link>http://geeks.ms/blogs/rfog/archive/tags/Win32/default.aspx</link><description>Etiquetas: Win32</description><dc:language /><generator>CommunityServer 2008.5 SP1 (Build: 31106.3070)</generator><item><title>Llamando al API de WinRT desde aplicaciones de escritorio normales en C#</title><link>http://geeks.ms/blogs/rfog/archive/2013/02/02/llamando-al-api-de-winrt-desde-aplicaciones-de-escritorio-normales-en-c.aspx</link><pubDate>Sat, 02 Feb 2013 14:09:00 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:208467</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=208467</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/rfog/commentapi.aspx?PostID=208467</wfw:comment><comments>http://geeks.ms/blogs/rfog/archive/2013/02/02/llamando-al-api-de-winrt-desde-aplicaciones-de-escritorio-normales-en-c.aspx#comments</comments><description>&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p align="justify"&gt;&lt;span style="color:#ff00ff;"&gt;&lt;strong&gt;&lt;span style="text-decoration:underline;"&gt;&lt;/span&gt;&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;strong&gt;&lt;span style="font-family:mceinline;"&gt;NOTA IMPORTANTE:&lt;/span&gt;&lt;/strong&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p align="justify"&gt;Esta entrada est&amp;aacute; obsoleta porque lo que describo m&amp;aacute;s abajo no funciona tal y como est&amp;aacute; contado. Es un &lt;i&gt;mea culpa&lt;/i&gt;&amp;nbsp;en toda propiedad por no haber probado antes lo que escrib&amp;iacute;a, pero es que la entrada original es bastante cre&amp;iacute;ble.&lt;/p&gt;
&lt;p align="justify"&gt;Eso me llev&amp;oacute; a crear un nuevo art&amp;iacute;culo, esta vez verificado, que se puede leer aqu&amp;iacute;:&lt;/p&gt;
&lt;p align="justify"&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1 class="title"&gt;&lt;a target="_blank" href="http://msdn.microsoft.com/es-es/library/dn126142.aspx"&gt;Llamando al API de WinRT desde aplicaciones de escritorio normales en C#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p align="justify"&gt;******************************************************&lt;/p&gt;
&lt;p align="justify"&gt;El otro d&amp;iacute;a &lt;a href="https://twitter.com/elrfog/status/297107885199093760"&gt;twite&amp;eacute;&lt;/a&gt; un &lt;a href="http://www.hanselman.com/blog/HowToCallWinRTAPIsInWindows8FromCDesktopApplicationsWinRTDiagram.aspx"&gt;enlace&lt;/a&gt; que ten&amp;iacute;a apuntado por ah&amp;iacute; y que no hab&amp;iacute;a le&amp;iacute;do hasta el momento del twitt, como me pasa con una docena m&amp;aacute;s, que tengo en la lista de encontrar tiempo y tranquilidad para leerlos en detalle.&lt;/p&gt;
&lt;p align="justify"&gt;Y como creo que deber&amp;iacute;a estar en castellano, os voy a contar de qu&amp;eacute; va la cosa.&lt;/p&gt;
&lt;p align="justify"&gt;Todos sabemos que ahora hay dos Windows 8. El tradicional de toda la vida y el RT. A ver, son el mismo, pero a la vez diferentes. El RT es la versi&amp;oacute;n para tabletas, que en teor&amp;iacute;a permite desarrollar usando s&amp;oacute;lo un subconjunto de Win32 y de .NET, pese a que por debajo sigue estando el Windows de toda la vida.&lt;/p&gt;
&lt;p align="justify"&gt;La otra versi&amp;oacute;n es la normal, la del escritorio pleno y funcional a la que estamos acostumbrados, que a su vez usa el API tradicional, ya sea el nativo Win32 o el de .NET. &lt;/p&gt;
&lt;p align="justify"&gt;Y si bien est&amp;aacute; prohibido usar el API completo en las aplicaciones RT, lo contrario no es as&amp;iacute; ya que en el escritorio tenemos plena libertad para utilizar cualquier cosa, incluyendo el API de Windows RT. Lo que ocurre es que el soporte directo para ello est&amp;aacute; ausente en las versiones de Visual Studio.&lt;/p&gt;
&lt;p align="justify"&gt;Pero se puede hacer editando el texto plano del fichero de nuestro proyecto: &amp;lt;proyecto&amp;gt;.csproj. Ah&amp;iacute; dentro debemos a&amp;ntilde;adir las l&amp;iacute;neas&lt;/p&gt;
&lt;p align="justify"&gt;&amp;lt;propertygroup&amp;gt;&lt;/p&gt;
&lt;p align="justify"&gt;&amp;lt;targetplatformversion&amp;gt;8.0&amp;lt;/targetplatformversion&amp;gt;&lt;/p&gt;
&lt;p align="justify"&gt;&amp;lt;/propertygroup&amp;gt;&lt;/p&gt;
&lt;p align="justify"&gt;Y a partir de ah&amp;iacute;, una vez recargado el mismo, podremos usar el API de Windows RT con s&amp;oacute;lo a&amp;ntilde;adir las referencias adecuadas seg&amp;uacute;n se vayan necesitando. El mayor problema es que tenemos que saber cu&amp;aacute;les son y a&amp;ntilde;adirlas a mano.&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_image001_5F00_14CC9A47.png"&gt;&lt;img height="98" width="244" src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rfog/clip_5F00_image001_5F00_thumb_5F00_7AF86417.png" alt="clip_image001" border="0" style="border-top:0px;border-right:0px;border-bottom:0px;border-left:0px;display:inline;" title="clip_image001" /&gt;&lt;/a&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_image003_5F00_6C4DB832.jpg"&gt;&lt;img height="141" width="244" src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rfog/clip_5F00_image003_5F00_thumb_5F00_5FDF9509.jpg" alt="clip_image003" border="0" style="border-top:0px;border-right:0px;border-bottom:0px;border-left:0px;display:inline;" title="clip_image003" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=208467" width="1" height="1"&gt;</description><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/C_2300_/default.aspx">C#</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/Win32/default.aspx">Win32</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/Windows+8/default.aspx">Windows 8</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/Windows+RT/default.aspx">Windows RT</category></item><item><title>C++/CX (III). Objetos COM</title><link>http://geeks.ms/blogs/rfog/archive/2012/05/18/c-cx-iii-objetos-com.aspx</link><pubDate>Fri, 18 May 2012 14:14:09 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:205115</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=205115</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/rfog/commentapi.aspx?PostID=205115</wfw:comment><comments>http://geeks.ms/blogs/rfog/archive/2012/05/18/c-cx-iii-objetos-com.aspx#comments</comments><description>&lt;p style="margin:0.0px 0.0px 0.0px 0.0px;text-align:justify;text-indent:18.0px;font:14.0px Calibri;"&gt;Decíamos &lt;a href="http://geeks.ms/blogs/rfog/archive/2011/11/04/c-cx-ii-c-cx-vs-wrl.aspx"&gt;ayer&lt;/a&gt; y &lt;a href="http://geeks.ms/blogs/rfog/archive/2011/10/31/c-cx-windows-8-y-el-nuevo-subsistema-winrt-i.aspx"&gt;antes de ayer&lt;/a&gt; que para crear aplicaciones Metro en Windows 8 podíamos usar, o bien el .NET Framework 4.5 con C# y &lt;a href="http://VB.NET"&gt;VB.NET&lt;/a&gt; o bien hacerlo con el tradicional C++. Ya conocemos que Microsoft se ha dado cuenta de que la &lt;em&gt;cosa manejada&lt;/em&gt; no deja de ser un poco juguete comparada con la nativa, y que hay muchísimas empresas que siguen, no solo con C++, sino incluso con MFC.&lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 0.0px;text-align:justify;text-indent:18.0px;font:14.0px Calibri;"&gt;Independientemente de eso, lo cierto es que el API para Metro no es más que una variación de Win32, empaquetada y ofrecida mediante objetos COM nativos. La idea es cambiar Win32 y prohibirla para Metro, ofreciendo su equivalente mediante la biblioteca WRL que no es más que un encapsulado exportado mediante COM.&lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 0.0px;text-align:justify;text-indent:18.0px;font:14.0px Calibri;"&gt;Aquí parece como si Microsoft matara dos pájaros de un tiro, ya que .NET utiliza COM internamente, o lo más parecido y cercano a ello. Por lo tanto, lo exportado mediante la WRL es tomado, por un lado por .NET y por el otro por C++ con su extensión CX.&lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 0.0px;text-align:justify;text-indent:18.0px;font:14.0px Calibri;"&gt;Tenemos que decir que C++/CX es código nativo. Sin recolector de basura. Sin máquina virtual.  Compilado para un procesador específico. No es más que nuestro código escrito en C++ que utiliza objetos COM envueltos en una serie de clases &lt;em&gt;al estilo de .NET&lt;/em&gt;. De hecho, la sintaxis de C++/CX es la misma que la de C++/CLI, por lo que en un principio puede llevar a confusión.&lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 0.0px;text-align:justify;text-indent:18.0px;font:14.0px Calibri;"&gt;De todos modos, para aquellos que hayan leído el &lt;a href="http://www.gotw.ca/publications/C++CLIRationale.pdf"&gt;&lt;em&gt;Rationale&lt;/em&gt; de Sutter&lt;/a&gt; (&lt;a href="http://rfog.cmact.com/inicio.htm"&gt;versión en español de Octavio Hernández y del que suscribe aquí&lt;/a&gt;), sabrán que es la única otra sintaxis posible y, o bien escribimos en C++/CLI para el .NET clásico (léase Windows Forms) o bien lo hacemos en C++/CX para Metro. Y si bien podemos hacer ambas cosas para Windows 8, las aplicaciones C++/CLI serán las tradicionales, y las C++/CX las Metro.&lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 0.0px;text-align:justify;text-indent:18.0px;font:14.0px Calibri;"&gt;Con esto queremos decir que, usando C++/CX, tenemos acceso a toda la parafernalia nativa de C++ como la STL, Boost, C++11… y encima desarrollar para Metro. O dicho de otro modo: cualquier código que tengamos que no haga uso de ventanas ni de Win32 de forma directa no servirá para las aplicaciones Metro.&lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 0.0px;text-align:justify;text-indent:18.0px;font:14.0px Calibri;"&gt;***&lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 0.0px;text-align:justify;text-indent:18.0px;font:14.0px Calibri;"&gt;La parte CX se activa con la opción /ZW del compilador, y lo que hace es mapear los objetos COM en clases normales y corrientes. Allí donde antes teníamos que enfangarnos con &lt;em&gt;IInspectable&lt;/em&gt;, y usar toda la parafernalia COM, ahora simplemente tenemos que usar una&lt;em&gt; ref class&lt;/em&gt; normal y corriente con sus constructores, destructores, propiedades, delegados y métodos que recibirán los tipos de datos más estándar y que devolverán también valores estándar.&lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 0.0px;text-align:justify;text-indent:18.0px;font:14.0px Calibri;"&gt;O en otras palabras: las clases que nos ofrece el API de Metro (por llamarlo de alguna manera, ya que es el API de WRL) son envoltorios a objetos COM WRL. Y de igual forma que los programadores de Windows han construido la WRL, nosotros también podremos tener objetos del mismo tipo, hechos por nosotros y ofrecidos a terceros. &lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 0.0px;text-align:justify;text-indent:18.0px;font:14.0px Calibri;"&gt;Supongamos que tenemos una clase cualquiera con un método llamado &lt;em&gt;Compute &lt;/em&gt;que toma dos enteros y devuelve un valor de estado. Para nosotros, que usamos dicha clase, tan sólo tenemos que llamar al método y esperar el resultado.&lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 0.0px;text-align:justify;text-indent:18.0px;font:14.0px Calibri;"&gt;Pero internamente, lo que está haciendo el &lt;em&gt;sugar syntax&lt;/em&gt; de la parte CX del compilador, es algo así:&lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 0.0px;text-align:justify;text-indent:18.0px;font:14.0px Calibri;min-height:17.0px;"&gt; &lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 36.0px;font:10.0px Consolas;"&gt;//Parte del “consumidor” de la case&lt;br /&gt; inline int Computer::Compute(int first, int second) { &lt;br /&gt;     int result; &lt;br /&gt;     HRESULT hr = ___impl_Compute(this, first, second, &amp;amp;result); &lt;br /&gt;     if (hr != 0) ___impl_throw_for_hr(hr); &lt;br /&gt;     return result; &lt;br /&gt; } &lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 36.0px;font:10.0px Calibri;min-height:13.0px;"&gt; &lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 0.0px;text-align:justify;text-indent:18.0px;font:14.0px Calibri;"&gt;Y luego, el método &lt;em&gt;__impl_Compute&lt;/em&gt;, que está en el lado del componente (si fuera una clase WRL estaría &lt;em&gt;dentro&lt;/em&gt; de la WRL), sería algo así:&lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 0.0px;text-align:justify;text-indent:18.0px;font:14.0px Calibri;min-height:17.0px;"&gt; &lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 36.0px;font:10.0px Calibri;"&gt;HRESULT __stdcall ___impl_Compute(Computer* cmp, &lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 36.0px;font:10.0px Calibri;"&gt;  int first, int second, int* result) { &lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 36.0px;font:10.0px Calibri;"&gt;    try { *result = cmp-&amp;gt;Compute(first, second); } &lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 36.0px;font:10.0px Calibri;"&gt;    catch(Platform::Exception^ e) { return e-&amp;gt;HResult; } &lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 36.0px;font:10.0px Calibri;"&gt;    return S_OK; &lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 36.0px;font:10.0px Calibri;"&gt;}&lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 0.0px;text-align:justify;text-indent:18.0px;font:14.0px Calibri;min-height:17.0px;"&gt; &lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 0.0px;text-align:justify;text-indent:18.0px;font:14.0px Calibri;"&gt;De este modo vemos cómo podemos acceder a un método sin toda la parafernalia ni las ofuscaciones de COM. Y no queremos entrar en detalles sobre por qué COM es tan &lt;em&gt;así&lt;/em&gt;, mayormente porque no tenemos ni repajolera idea.&lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 0.0px;text-align:justify;text-indent:18.0px;font:14.0px Calibri;"&gt;No obstante, si así lo queremos por detalles de la implementación o simplemente por ser &lt;em&gt;guays&lt;/em&gt;, tenemos acceso a la parte interna de WRL de la siguiente manera:&lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 0.0px;text-align:justify;text-indent:18.0px;font:14.0px Calibri;min-height:17.0px;"&gt; &lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 36.0px;font:10.0px Calibri;"&gt;//Assuming 32-bit pointers &lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 36.0px;font:10.0px Calibri;"&gt;Computer^ computer = ref new Computer; &lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 36.0px;font:10.0px Calibri;"&gt;int* vtable_array = (int*)computer; &lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 36.0px;font:10.0px Calibri;"&gt;int* icomputer_vtable = (int*)vtable_array[0]; &lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 36.0px;font:10.0px Calibri;"&gt;int* compute_will_be_fptr = (int*)icomputer_vtable[6]; &lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 36.0px;font:10.0px Calibri;"&gt;typedef HRESULT (__stdcall *compute_fptr_t)(Computer*, &lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 36.0px;font:10.0px Calibri;"&gt;  int, int, int*); &lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 36.0px;font:10.0px Calibri;"&gt;compute_fptr_t compute_fptr = (compute_fptr_t)compute_will_be_fptr; &lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 36.0px;font:10.0px Calibri;"&gt;//…use compute_fptr freely :-)&lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 0.0px;text-align:justify;text-indent:18.0px;font:14.0px Calibri;min-height:17.0px;"&gt; &lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 0.0px;text-align:justify;text-indent:18.0px;font:14.0px Calibri;"&gt;No voy a comentar nada de aquí porque simplemente me parece algo demasiado barroco y supongo que sólo será útil si te encuentras con algún bug en la parte CX del compilador… También podemos acceder a la interfaz COM pura a través del método &lt;em&gt;RoActivateInstance&lt;/em&gt;, pero lo dejamos para los &lt;em&gt;hardcore&lt;/em&gt;.&lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 0.0px;text-align:justify;text-indent:18.0px;font:14.0px Calibri;"&gt;***&lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 0.0px;text-align:justify;text-indent:18.0px;font:14.0px Calibri;"&gt;Finalmente hay una opción del compilador no documentada para que éste nos muestre una estructura detallada del componente WinRT que especifiquemos: &lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 0.0px;text-align:justify;text-indent:18.0px;font:14.0px Calibri;min-height:17.0px;"&gt; &lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 36.0px;font:10.0px Calibri;"&gt;/d1reportSingleClassLayout&amp;lt;CLASSNAME&amp;gt;&lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 0.0px;text-align:justify;text-indent:18.0px;font:14.0px Calibri;min-height:17.0px;"&gt; &lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 0.0px;text-align:justify;text-indent:18.0px;font:14.0px Calibri;"&gt;Y de nuevo dejamos la opción para los &lt;em&gt;aventureros&lt;/em&gt;, que yo ya me he cansado de escribir por hoy.&lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 0.0px;text-align:justify;text-indent:18.0px;font:14.0px Calibri;min-height:17.0px;"&gt; &lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=205115" width="1" height="1"&gt;</description><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/Win32/default.aspx">Win32</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/Biblioteca+de+C_2B002B00_/default.aspx">Biblioteca de C++</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>¿WinRT un subsistema? No, no lo es</title><link>http://geeks.ms/blogs/rfog/archive/2011/11/02/191-winrt-un-subsistema-no-no-lo-es.aspx</link><pubDate>Wed, 02 Nov 2011 16:41:00 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:201435</guid><dc:creator>Rafael Ontivero</dc:creator><slash:comments>3</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/rfog/rsscomments.aspx?PostID=201435</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/rfog/commentapi.aspx?PostID=201435</wfw:comment><comments>http://geeks.ms/blogs/rfog/archive/2011/11/02/191-winrt-un-subsistema-no-no-lo-es.aspx#comments</comments><description>&lt;p&gt;Bueno, al final no ha costado mucho encontrarlo. B&amp;aacute;sicamente, el resultado de esta investigaci&amp;oacute;n es:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rfog/image_5F00_4ACD74FC.png"&gt;&lt;img height="138" width="244" src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rfog/image_5F00_thumb_5F00_08EBB110.png" alt="image" border="0" title="image" style="background-image:none;border-bottom:0px;border-left:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;border-top:0px;border-right:0px;padding-top:0px;" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;O con otras palabras: WinRT y Metro se ejecutan, como todo lo dem&amp;aacute;s, sobre Win32, con las ventajas y los inconvenientes que eso pueda tener. No me malinterpret&amp;eacute;is: no hay nada malo que la arquitectura sea diferente a la indicada en el gr&amp;aacute;fico de arriba, lo que est&amp;aacute; mal es que Microsoft nos mienta tan descaradamente. Simplemente eso.&lt;/p&gt;
&lt;p&gt;Si lo han hecho as&amp;iacute;, por algo ser&amp;aacute; y sus motivos tendr&amp;aacute;n, y es entonces cuando, ya definitivamente, yo ten&amp;iacute;a raz&amp;oacute;n: Windows ya no es Windows NT, y su grandiosa arquitectura por bloques se ha perdido en el camino. Y esto s&amp;iacute; que es malo, bastante malo, porque estamos volviendo a un batiburrillo de c&amp;oacute;digo como es, por cierto, el OS X (quiz&amp;aacute;s alg&amp;uacute;n d&amp;iacute;a hable de ello).&lt;/p&gt;
&lt;p&gt;Vosotros mismos pod&amp;eacute;is comprobarlo sin problema alguno y de forma muy r&amp;aacute;pida. Ten&amp;eacute;is que construir dos aplicaciones, una WinRT en C++/CX y otra cl&amp;aacute;sica de Win32. No hay m&amp;aacute;s que utilizar las plantillas por defecto sin ning&amp;uacute;n cambio.&lt;/p&gt;
&lt;p&gt;Eso s&amp;iacute;, hay que hacerlo a partir de la versi&amp;oacute;n Developer de 64 bits de Windows 8, e instalar una versi&amp;oacute;n de la MSDN, porque la Express creo que no es capaz de generar programas Win32 puros.&lt;/p&gt;
&lt;p&gt;He llamado &amp;ldquo;TestWin32&amp;rdquo; a mi aplicaci&amp;oacute;n tradicional, que genera una ventana de Windows normal y corriente utilizando directamente el API de Win32. A la Metro la he llamado &amp;ldquo;TestSplitApplication&amp;rdquo;. Una vez generadas, tenemos que compilarlas. Visual Studio se os quedar&amp;aacute; m&amp;aacute;s o menos as&amp;iacute;:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rfog/image_5F00_33C6A5D3.png"&gt;&lt;img height="161" width="244" src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rfog/image_5F00_thumb_5F00_55B49908.png" alt="image" border="0" title="image" style="background-image:none;border-bottom:0px;border-left:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;border-top:0px;border-right:0px;padding-top:0px;" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Si ahora nos vamos a la carpeta en donde est&amp;aacute; almacenado el proyecto (que podemos hacer desde el mismo IDE posicion&amp;aacute;ndonos en el nombre de la soluci&amp;oacute;n en el Explorador y elegimos &lt;i&gt;Open Folder in Windows Explorer&lt;/i&gt;), carpeta &lt;i&gt;Debug&lt;/i&gt;, encontraremos el ejecutable del programa nativo (&lt;i&gt;TestWin32.exe&lt;/i&gt;) y dentro de la carpeta &lt;i&gt;TestSplitApplication&lt;/i&gt;, el de la aplicaci&amp;oacute;n Metro.&lt;/p&gt;
&lt;p&gt;(Por cierto, en uno de esos lapsus teclae tan habituales en mi, le he dado el nombre de &amp;ldquo;TestSplitApplicarion&amp;rdquo; en lugar del correcto.)&lt;/p&gt;
&lt;p&gt;Ahora debemos conseguir el &lt;a href="http://www.dependencywalker.com/"&gt;&lt;i&gt;Dependency Walker&lt;/i&gt;&lt;/a&gt;, aunque existen otras herramientas de l&amp;iacute;nea de comandos que nos permiten hacer lo mismo dentro del SDK, lo interesante es utilizar esta porque lo veremos todo de un golpe. El mayor problema es que se trata de una utilidad que hace tiempo que no se incluye en ning&amp;uacute;n SDK, por lo que hay que conseguirla de &lt;a href="http://www.dependencywalker.com/"&gt;forma externa&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Una vez obtenida la versi&amp;oacute;n de 32 bits, porque nuestros proyectos son de dicho tipo, la ejecutamos sobre cada uno de los dos programas. Este es el resultado:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rfog/image_5F00_7E53050F.png"&gt;&lt;img height="161" width="244" src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rfog/image_5F00_thumb_5F00_19B00966.png" alt="image" border="0" title="image" style="background-image:none;border-bottom:0px;border-left:0px;margin:5px 5px 5px 0px;padding-left:0px;padding-right:0px;display:inline;border-top:0px;border-right:0px;padding-top:0px;" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;iquest;Lo veis? Ambos programas importan las mismas DLL, las de Win32 como KERNEL32.DLL y USER32.DLL.&lt;/p&gt;
&lt;p&gt;Es decir que ambos son aplicaciones Win32 nativas.&lt;/p&gt;
&lt;p&gt;***&lt;/p&gt;
&lt;p&gt;Si nos diera por abrir, por ejemplo, uno de los dos KERNEL32.DLL, ver&amp;iacute;amos que ambas DLL son la misma con las mismas dependencias y exportaciones. Por lo tanto, ambas aplicaciones dependen del mismo subsistema.&lt;/p&gt;
&lt;p&gt;Reitero que es una tonter&amp;iacute;a, pero no lo es cuando intentan enga&amp;ntilde;arte.&lt;/p&gt;
&lt;p&gt;Lo que s&amp;iacute; parece han hecho ha sido &lt;i&gt;romper&lt;/i&gt; KERNEL32.DLL en otros ficheros m&amp;aacute;s peque&amp;ntilde;os que contemplan subconjuntos de lo que en versiones anteriores hab&amp;iacute;a en &amp;eacute;l. Quiz&amp;aacute;s de esta forma reduzcan la huella de memoria evitando cargar sub ficheros cuando estos no se vayan a utilizar.&lt;/p&gt;
&lt;p&gt;***&lt;/p&gt;
&lt;p&gt;Esto nos lleva a un tercer problema: parecer ser que una aplicaci&amp;oacute;n Metro no puede ejecutar funciones de Win32, y una de Win32 tampoco de WinRT.&lt;/p&gt;
&lt;p&gt;&amp;iexcl;&amp;iexcl;Pero si es el mismo subsistema!!&lt;/p&gt;
&lt;p&gt;Pues bien, estamos ante una limitaci&amp;oacute;n artificialmente impuesta por Microsoft sin ning&amp;uacute;n motivo t&amp;eacute;cnico aparente&amp;hellip; con lo guapo que ser&amp;iacute;a hacer aplicaciones Win32 con C++/CX&amp;hellip;&lt;/p&gt;
&lt;p&gt;Se me ocurren un par de trucos para poder forzar esto, pero no creo que valga la pena hacerlo en una versi&amp;oacute;n tan temprana como esta. Quiz&amp;aacute;s cuando salga la definitiva, si tengo ganas y si nadie m&amp;aacute;s se me adelanta, lo intente.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=201435" 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/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/rationale/default.aspx">rationale</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/Win32/default.aspx">Win32</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/Biblioteca+de+C_2B002B00_/default.aspx">Biblioteca de C++</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></item><item><title>C++/CX  (I). Windows 8 y el nuevo subsistema WinRT</title><link>http://geeks.ms/blogs/rfog/archive/2011/10/31/c-cx-windows-8-y-el-nuevo-subsistema-winrt-i.aspx</link><pubDate>Mon, 31 Oct 2011 14:34:00 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:201432</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=201432</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/rfog/commentapi.aspx?PostID=201432</wfw:comment><comments>http://geeks.ms/blogs/rfog/archive/2011/10/31/c-cx-windows-8-y-el-nuevo-subsistema-winrt-i.aspx#comments</comments><description>&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rfog/image_5F00_47C30F25.png"&gt;&lt;img height="137" width="244" src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rfog/image_5F00_thumb_5F00_6774799E.png" alt="image" border="0" title="image" style="background-image:none;border-bottom:0px;border-left:0px;margin:5px auto;padding-left:0px;padding-right:0px;display:block;float:none;border-top:0px;border-right:0px;padding-top:0px;" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Observad con detalle la imagen de arriba. Fijaos en que est&amp;aacute; dividida en dos grandes bloques. A poco que os haya preocupado la arquitectura l&amp;oacute;gica de Windows, os dar&amp;eacute;is cuenta de que hay nueva chica en la oficina: WinRT. &lt;/p&gt;
&lt;p&gt;Ya habl&amp;eacute; de algo as&amp;iacute; &lt;a href="http://geeks.ms/blogs/rfog/archive/2011/03/19/mac-rationale-vs-windows-rationale-en-el-desarrollo.aspx"&gt;aqu&amp;iacute;&lt;/a&gt;, pero en relaci&amp;oacute;n con la arquitectura de Apple comparada con la de Windows, y de los &amp;uacute;ltimos cambios que Microsoft ha ido haciendo para adecuar su plataforma NT para que sea funcional y &amp;uacute;til para el usuario medio, dejando un poco de lado la arquitectura tradicional.&lt;/p&gt;
&lt;p&gt;Pues bien, parece ser que me tengo que comer mis palabras con patatas (no, no &lt;i&gt;esas patatas&lt;/i&gt;, Z). Volviendo al gr&amp;aacute;fico anterior, WinRT es un nuevo subsistema igual que lo es Win32. Para aquellos que no tengan claro qu&amp;eacute; es, os cuento un poco la arquitectura te&amp;oacute;rica de Windows NT.&lt;/p&gt;
&lt;p&gt;El sistema operativo cuenta con un kernel (s&amp;iacute;, como el de Linux, pero con muchas m&amp;aacute;s cosas dentro de &amp;eacute;l y mucho m&amp;aacute;s din&amp;aacute;mico), que en teor&amp;iacute;a se asienta sobre una capa HAL que abstrae a dicho n&amp;uacute;cleo de la arquitectura f&amp;iacute;sica. En su momento hubo HAL para ARM y para otras plataformas. En la actualidad s&amp;oacute;lo la hay para x86, tanto en versi&amp;oacute;n de 32 como de 64 bits.&lt;/p&gt;
&lt;p&gt;O eso cre&amp;iacute;a tras haber hecho un somero an&amp;aacute;lisis de las tripas de Windows 7. Pues bien, si Microsoft a&amp;ntilde;ade soporte para ARM (y recordemos que van a salir procesadores de este tipo de 64 bits), dicha capa debe ser o bien reimplementada o bien ya exist&amp;iacute;a y simplemente estaba inactiva. O lo que me parece m&amp;aacute;s l&amp;oacute;gico: recompilar todo el sistema operativo para que se ejecute en dicha arquitectura, cambiando lo que haya que cambiar, dado que eso de traducir cualquier otro procesador a x86, sobre todo desde un ARM, suena a fantas&amp;iacute;a animada de ayer y de hoy.&lt;/p&gt;
&lt;p&gt;Por otro lado, Windows se mueve mediante subsistemas. Uno de ellos es Win32. Otro lo fue OS/2 y tambi&amp;eacute;n Posix (s&amp;iacute;, en un pasado lejano, Windows NT era capaz de ejecutar comandos de unix con las primitivas de desarrollo que tiene la parte est&amp;aacute;ndar Posix de Unix). Es decir, un subsistema suministra cierta abstracci&amp;oacute;n sobre el n&amp;uacute;cleo, proporcionando un API mucho m&amp;aacute;s rico y potente. Y de paso lo a&amp;iacute;sla para que las aplicaciones sean incapaces de tumbarlo.&lt;/p&gt;
&lt;p&gt;En otras palabras, Win32 se ejecuta en el anillo 3 y el n&amp;uacute;cleo en el cero, y es Win32 el que, cuando una aplicaci&amp;oacute;n pide alg&amp;uacute;n recursos del sistema (por ejemplo un puerto serie), el que se encarga de mover la petici&amp;oacute;n y de realizar tareas intermedias, evitando as&amp;iacute; que un mal uso por parte de una aplicaci&amp;oacute;n genere una pantalla azul. &lt;/p&gt;
&lt;p&gt;Digamos que una aplicaci&amp;oacute;n en el anillo 3 jam&amp;aacute;s podr&amp;aacute; tumbar al sistema ejecut&amp;aacute;ndose en el anillo 0, o al menos esa es la teor&amp;iacute;a. A veces un par&amp;aacute;metro mal pasado puede terminar en una ca&amp;iacute;da completa, pero no es lo habitual, y cada vez menos.&lt;/p&gt;
&lt;p&gt;Pues bien, aparte de Win32, ahora tenemos un nuevo subsistema llamado WinRT. O eso dice, al menos la teor&amp;iacute;a y as&amp;iacute; nos lo presenta Microsoft en sus gr&amp;aacute;ficos y en la escas&amp;iacute;sima informaci&amp;oacute;n de la que disponemos.&lt;/p&gt;
&lt;p&gt;Una de mis pr&amp;oacute;ximas tareas es la de intentar averiguar si esto es as&amp;iacute; o no lo es. No es la primera vez que Microsoft miente descaradamente, como cuando dijo de XAML no iba a necesitar de Win32 y que desaparec&amp;iacute;an los bucles de mensajes y que se ejecutar&amp;iacute;a sobre DirectX&amp;hellip; Hasta donde s&amp;eacute;, todav&amp;iacute;a eso no es del todo cierto.&lt;/p&gt;
&lt;p&gt;Tambi&amp;eacute;n nos dijo que .NET iba a ser un subsistema, y realmente se ha quedado como una capa sobre Win32&amp;hellip;&lt;/p&gt;
&lt;p&gt;Por lo tanto, estad atentos al blog. Adem&amp;aacute;s, el dibujo original de Microsoft deja mucho que desear respecto a la claridad, presentando Internet Explorer y .NET como subsistemas independientes de Win32, lo que es, a todas luces, completamente falso:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rfog/image_5F00_3B577CAD.png"&gt;&lt;img height="138" width="244" src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rfog/image_5F00_thumb_5F00_0E673B34.png" alt="image" border="0" title="image" style="background-image:none;border-bottom:0px;border-left:0px;margin:5px auto;padding-left:0px;padding-right:0px;display:block;float:none;border-top:0px;border-right:0px;padding-top:0px;" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;***&lt;/p&gt;
&lt;p&gt;Volviendo al gr&amp;aacute;fico de arriba, podemos ver algunos detalles que creo no son del todo ciertos, pero nos dan una idea de la arquitectura del nuevo WinRT (sobre la que se basa la interfaz METRO que llevar&amp;aacute;, junto al escritorio tradicional, Windows 8).&lt;/p&gt;
&lt;p&gt;(Una de las cosas por las que dudo que WinRT sea un subsistema completo es el hecho de que Windows 8 consuma menos memoria que el 7 y de que se pueda producir ese intercambio tan r&amp;aacute;pido entre los dos escritorios, lo que me hace pensar que, de nuevo, se trata de algo sobre Win32).&lt;/p&gt;
&lt;p&gt;En WinRT hay dos interfaces de desarrollo principales: XAML y HTML. Es decir, podemos hacer aplicaciones &lt;i&gt;cl&amp;aacute;sicas&lt;/i&gt; basadas en el primer modelo y &lt;i&gt;modernas&lt;/i&gt; en el segundo.&lt;/p&gt;
&lt;p&gt;A simple vista puede parecer que en ambas se utiliza una misma variaci&amp;oacute;n del XML, pero no es as&amp;iacute;. En el caso de HTML/CSS nuestra aplicaci&amp;oacute;n no ser&amp;aacute; otra cosa m&amp;aacute;s que una &lt;i&gt;p&amp;aacute;gina web&lt;/i&gt; ejecut&amp;aacute;ndose dentro de una sesi&amp;oacute;n m&amp;aacute;s o menos oculta de Internet Explorer. Tendremos acceso a esas dos tecnolog&amp;iacute;as (incluyendo HTML5) y JavaScript como &lt;i&gt;lenguaje&lt;/i&gt; de desarrollo. &lt;/p&gt;
&lt;p&gt;En el caso de XAML, estamos ante la &lt;i&gt;&amp;uacute;ltima&lt;/i&gt; evoluci&amp;oacute;n de las interfaces de usuario din&amp;aacute;micas en las que la interfaz est&amp;aacute; completamente (o lo m&amp;aacute;s posible) separada del c&amp;oacute;digo en s&amp;iacute;, lo que permite una soltura nunca vista hasta ahora. O al menos esa es la teor&amp;iacute;a y casi os dir&amp;iacute;a que la pr&amp;aacute;ctica.&lt;/p&gt;
&lt;p&gt;XAML es muy potente. Demasiado, casi dir&amp;iacute;a. Se trata de una especie de colecci&amp;oacute;n de contenedores jer&amp;aacute;rquicos que pueden actuar como tales o como elementos finales, y pueden &lt;i&gt;mutar&lt;/i&gt; de un tipo a otro con una facilidad pasmosa. De hecho, cambiar el aspecto visual de una aplicaci&amp;oacute;n XAML puede llegar a ser cosa de unas pocas &amp;ndash;muy pocas- l&amp;iacute;neas de c&amp;oacute;digo, con el a&amp;ntilde;adido de que quien haya desarrollado con .NET y la versi&amp;oacute;n anterior, est&amp;aacute; casi listo para esta nueva (que por cierto no es mi caso, pese a ver en su momento las ventajas evidentes del nuevo modelo).&lt;/p&gt;
&lt;p&gt;Por lo tanto, los programadores de .NET que hayan abandonado Windows Forms por la nueva forma, lo tendr&amp;aacute;n bastante f&amp;aacute;cil. Los dinosaurios como yo mismo tendremos ciertas dificultades en adaptarnos&amp;hellip; o no.&lt;/p&gt;
&lt;p&gt;&amp;iquest;Record&amp;aacute;is C++/CLI, el C++ del .NET? Pues bien, la &amp;uacute;nica pega para que dicha extensi&amp;oacute;n de C++ pudiera utilizar XAML es que no se soportan las clases parciales como en C o en VB.NET. Por desgracia, eso sigue siendo as&amp;iacute;, y la interfaz cl&amp;aacute;sica continua estando vedada para los programadores de C++ en .NET, quedando limitados a Windows Forms y a un IDE que no es que se muestre muy estable manejando el lenguaje&amp;hellip;&lt;/p&gt;
&lt;p&gt;***&lt;/p&gt;
&lt;p&gt;Bueno, ahora, por fin, entra C++/CX. &amp;iquest;Qu&amp;eacute; es? Nada m&amp;aacute;s y nada menos que una nueva extensi&amp;oacute;n a C++, con una sintaxis muy similar a C++/CLI pero con un prop&amp;oacute;sito muy diferente: el de soportar METRO y XAML. Y no, no es .NET. Es nativo.&lt;/p&gt;
&lt;p&gt;Supongo que Microsoft se plante&amp;oacute; ante una disyuntiva muy pero que muy gorda: el rendimiento de .NET es suficiente para un PC, pero no lo es para una plataforma m&amp;oacute;vil como una tableta. No estoy diciendo que sea malo, estoy diciendo que eso de tener una m&amp;aacute;quina virtual consumiendo memoria y recursos, un &lt;i&gt;jitter&lt;/i&gt; ejecut&amp;aacute;ndose detr&amp;aacute;s de todo, y un post-compilador pasando MSIL a c&amp;oacute;digo nativo no es de recibo para un Tablet.&lt;/p&gt;
&lt;p&gt;Delante de todos est&amp;aacute; el fracaso de Android. Por favor, absteneros fundamentalistas y otros p&amp;aacute;jaros de similar cala&amp;ntilde;a: Android es un fracaso. Puede que aguante unos cuantos a&amp;ntilde;os, pero terminar&amp;aacute; por caer estrepitosamente, tanto por problemas t&amp;eacute;cnicos (demasiado consumo de memoria, demasiada lentitud, demasiadas capas una encima de otra, demasiadas ca&amp;iacute;das) como por comerciales (demasiada fragmentaci&amp;oacute;n, demasiado abandono de terminales a medio hacer), etc..&lt;/p&gt;
&lt;p&gt;Por lo tanto, para competir en igualdad de condiciones, tenemos que darle ca&amp;ntilde;a a iOS. Se debe hacer algo similar, y ese algo es WinRT y C++/CX. No hay m&amp;aacute;quina virtual .NET, ni nada oculto (o eso quiero creer), tan solo un motor de ejecuci&amp;oacute;n, una interfaz y el propio sistema operativo. O en otras palabras: objetive-c, cocoa y lo que quiera que haya en el n&amp;uacute;cleo de iOS (parece ser que un BSD recortadito).&lt;/p&gt;
&lt;p&gt;Otro problema es la arquitectura. Ya se ha demostrado que x86 es demasiado pesado y demasiado hambriento de energ&amp;iacute;a como para ser &amp;uacute;til en el mercado m&amp;oacute;vil, por lo que hay que subirse al carro de ARM, que son micros mucho menos complejos y por tanto consumen mucho menos y andan m&amp;aacute;s &lt;i&gt;sueltos&lt;/i&gt;.&lt;/p&gt;
&lt;p&gt;Por lo tanto se necesita algo diferente, algo mucho m&amp;aacute;s liviano. Y eso, de nuevo, es WinRT. Por lo tanto, la combinaci&amp;oacute;n ganadora es C++/CX, XAML y, c&amp;oacute;mo no, C# y VB.NET corriendo sobre una variaci&amp;oacute;n de .NET llamada .NET 4.5 WinRT (y que funcionar&amp;aacute; m&amp;aacute;s lento y consumir&amp;aacute; m&amp;aacute;s bater&amp;iacute;a que una aplicaci&amp;oacute;n realizada con C++/CX).&lt;/p&gt;
&lt;p&gt;Pero el n&amp;uacute;cleo, el centro de todo, es C++ y WinRT. Luego est&amp;aacute; .NET, encima igual que en Win32. Como debe ser. Y de nuevo abst&amp;eacute;ngase fundamentalistas. Si lo han hecho por algo ser&amp;aacute;. Quien cae del &amp;aacute;rbol a tiempo todav&amp;iacute;a puede recuperarse.&lt;/p&gt;
&lt;p&gt;***&lt;/p&gt;
&lt;p&gt;C++/CX no es .NET. Es nativo. Y la parte CX no es m&amp;aacute;s que un envoltorio c&amp;oacute;mo para los interfaces COM, ese animal mitol&amp;oacute;gico con el que los programadores de C++ nos tenemos que enfrentar de tiempo en tiempo y que nos pone los pelos de punta.&lt;/p&gt;
&lt;p&gt;Es decir, la parte CX s&amp;oacute;lo se utiliza para interactuar con XAML y los componentes que se hayan creado a tal efecto. Luego, nuestro c&amp;oacute;digo ser&amp;aacute; C++ normal y corriente, con la STL, los &lt;i&gt;streams&lt;/i&gt; (que personalmente pienso que no son muy &amp;uacute;tiles), Boost o lo que queramos usar y est&amp;eacute; disponible. Desarrollo determinista por completo, sin recolector de basura (a no ser que nos hagamos uno), sin elementos ocultos excepto el envolvente COM que han llamado CX y que nos servir&amp;aacute; para interactuar con los componentes.&lt;/p&gt;
&lt;p&gt;Otra ventaja de C++/CX sobre .NET es que, si quieres hacer un juego sobre DirectX, tendr&amp;aacute;s que usarlo ya que ni C# ni VB.NET est&amp;aacute;n soportados, de nuevo como debe ser.&lt;/p&gt;
&lt;p&gt;Ah, y con soporte para clases parciales, lo que&amp;hellip; bueno, mejor lo dejamos para m&amp;aacute;s adelante.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=201432" 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/Sistemas+Operativos/default.aspx">Sistemas Operativos</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/windows/default.aspx">windows</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><category domain="http://geeks.ms/blogs/rfog/archive/tags/Biblioteca+de+C_2B002B00_/default.aspx">Biblioteca de C++</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/C_2B002B002F00_CX/default.aspx">C++/CX</category></item><item><title>MAC Rationale vs Windows Rationale en el desarrollo</title><link>http://geeks.ms/blogs/rfog/archive/2011/03/19/mac-rationale-vs-windows-rationale-en-el-desarrollo.aspx</link><pubDate>Sat, 19 Mar 2011 14:42:00 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:190697</guid><dc:creator>Rafael Ontivero</dc:creator><slash:comments>2</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/rfog/rsscomments.aspx?PostID=190697</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/rfog/commentapi.aspx?PostID=190697</wfw:comment><comments>http://geeks.ms/blogs/rfog/archive/2011/03/19/mac-rationale-vs-windows-rationale-en-el-desarrollo.aspx#comments</comments><description>&lt;p&gt;
&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES"&gt;Todav&amp;iacute;a estoy leyendo temas generales sobre el
desarrollo en MAC, de hecho a&amp;uacute;n no he pasado de los manuales que describen las
tecnolog&amp;iacute;as y los diferentes bloques en que se divide el desarrollo en MAC. &lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES"&gt;No obstante me ha surgido una curiosa
reflexi&amp;oacute;n que quiero compartir con vosotros. Todav&amp;iacute;a no estoy muy seguro de que
sea completamente cierta, porque todav&amp;iacute;a no he profundizado en los conceptos
MAC y lo que he le&amp;iacute;do tiene m&amp;aacute;s que ver con la &lt;i&gt;publicidad&lt;/i&gt; del desarrollo en esta plataforma que otra cosa, pero
creo que tiene muchos visos de ser real como la vida misma.&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES"&gt;Y lo m&amp;aacute;s curioso de todo es que tiene mucho
que ver con el desarrollo Windows, y m&amp;aacute;s cercanamente al de las tecnolog&amp;iacute;as
.NET. Cuanto m&amp;aacute;s leo sobre Cocoa, QuickTime (que no s&amp;oacute;lo es un programa sino una
tecnolog&amp;iacute;a), etc., m&amp;aacute;s me parece estar leyendo sobre .NET, o m&amp;aacute;s bien sobre la
forma en la que se publicita .NET.&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES"&gt;Se habla de grandes grupos de tecnolog&amp;iacute;as
orientadas a objetos, con grandes rendimientos y grandes facilidades ofrecidas
a los desarrolladores. Calcado uno de otro. Ahora habr&amp;aacute; que ver la pura
realidad.&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES"&gt;Del lado .NET ya lo tengo claro: mucho ruido y
pocas nueces, al menos para desarrollo de sistemas. Quiero creer que del lado
MAC no ser&amp;aacute; igual, pero cualquiera sabe. Ya os ir&amp;eacute; diciendo.&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES"&gt;***&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES"&gt;Pero no, no es sobre eso sobre lo que os
quer&amp;iacute;a hablar. Veamos por un lado la arquitectura l&amp;oacute;gica expresada por los
manuales de MAC, que creo es m&amp;aacute;s real que la dicha por los de Windows.&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES"&gt;Debajo del todo un ordenador de Apple hay un
Kernel BSD que no es otra cosa que una variante de UNIX igual que es Linux. Y
luego hay un sistema POSIX de toda la vida que de nuevo tiene que ver con el
mundo UNIX (que viene a ser como una serie de servicios que simplifican el
acceso al n&amp;uacute;cleo del sistema igual que una consola de comandos en Windows
permite trabajar con ficheros sin tener que tocarlo).&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES"&gt;Aunque Apple lo ha llamado Darwin, no deja de
ser lo que es, y de hecho Apple &lt;a href="http://www.opensource.apple.com/"&gt;publica
todo el c&amp;oacute;digo fuente&lt;/a&gt; de ello. Al ser un est&amp;aacute;ndar debe estar separado.
Realmente est&amp;aacute; separado. &lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES"&gt;Encima de eso hay una serie de capas, Cocoa,
Carbon, QuickTime. M&amp;aacute;s o menos. Pero lo que es cierto es que esos subsistemas
est&amp;aacute;n completamente separados del n&amp;uacute;cleo o m&amp;aacute;s bien &lt;i&gt;encima&lt;/i&gt; de &amp;eacute;l.&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES"&gt;En Windows creo que no es as&amp;iacute;. En su momento,
en las versiones NT originales s&amp;iacute; que lo era (o al menos as&amp;iacute; se publicitaba).
Recordemos la capa HAL que pod&amp;iacute;a ser para un mont&amp;oacute;n de procesadores y luego el
sistema NT Executive nativo, que corr&amp;iacute;a sobre dicha capa. Pero ahora, despu&amp;eacute;s
de la unificaci&amp;oacute;n con la plataforma 9x en lo que fue Windows XP dudo mucho que
siga si&amp;eacute;ndolo.&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES"&gt;Porque ahora no hay soporte para ARM, ni para
SuperH, ni para PPC. S&amp;oacute;lo Intel x86 y dando gracias. Me juego un gallifante a
que ahora est&amp;aacute; todo mezclado y revuelto (y de ah&amp;iacute; los problemas de Microsoft
para volver a a&amp;ntilde;adir soporte para ARM). Porque si no fuera as&amp;iacute; no se entender&amp;iacute;a
c&amp;oacute;mo puede funcionar el sistema de v&amp;iacute;deo sobre Win32 accediendo al driver que
est&amp;aacute; en el n&amp;uacute;cleo (s&amp;iacute;, ya s&amp;eacute;, anillos, &lt;i&gt;gateways&lt;/i&gt;
y todo eso, pero no voy por ah&amp;iacute;)&amp;hellip; &lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES"&gt;Bueno, quiz&amp;aacute;s en esto me equivoque, pero si
alguien me explicara c&amp;oacute;mo el hecho de reproducir un v&amp;iacute;deo dentro de un
navegador pueda generar una BSOD estando los sistemas separados, que me lo
diga. Porque me ha pasado. Y no una, sino varias veces. Putas ATI.&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES"&gt;De todos modos luego veremos alguna raz&amp;oacute;n m&amp;aacute;s
de ello y quiz&amp;aacute;s uno de los puntos m&amp;aacute;s fuertes de por qu&amp;eacute; Microsoft est&amp;aacute; un
poco contra la espada y la pared.&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES"&gt;***&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES"&gt;Apple ya lo ha hecho al menos dos veces y lo
va a hacer una m&amp;aacute;s. En x64 no va a haber Carbon, que es como se le llama al
subsistema que soporta programar en C y C++ de forma nativa. En x64 s&amp;oacute;lo vamos
a tener Cocoa (Objetive-C y Objetive-C++) y POSIX (que yo sepa). En su momento,
con el cambio de PPC a x86 repiti&amp;oacute; jugada, haciendo borr&amp;oacute;n y cuenta nueva y
forzando a muchas empresas de software a reescribir sus programas. Como cosa
curiosa os dir&amp;eacute; que Apple encarg&amp;oacute; a Adobe la creaci&amp;oacute;n de su iPhoto, iVideo y
dem&amp;aacute;s programas de esa plataforma y Adobe los mand&amp;oacute; a fre&amp;iacute;r esp&amp;aacute;rragos porque
estaban como locos rehaciendo sus propios programas. Creo que hubo otro cambio
rompedor m&amp;aacute;s en los MAC pero ahora no recuerdo qu&amp;eacute;.&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES"&gt;Bueno, el meollo del asunto est&amp;aacute; en que a
veces es conveniente hacer borr&amp;oacute;n y cuenta nueva. Hasta donde s&amp;eacute;, el API de MAC
OS X y el de iOS es un API moderno, orientado a objetos y bastante potente. Ya
os dir&amp;eacute; si realmente es cierto cuando me enfangue las manos con ello.&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES"&gt;***&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES"&gt;Ahora volvamos a Windows. Aquellos que hayan
le&amp;iacute;do sobre el tema, sabr&amp;aacute;n lo que son los &lt;i&gt;subsistemas&lt;/i&gt;.
Para los que no, una peque&amp;ntilde;a introducci&amp;oacute;n.&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES"&gt;Win32 es un subsistema. POSIX es un subsistema
(o lo era hasta que lo quitaron). De hecho, en las primeras versiones de NT
hab&amp;iacute;a hasta un subsistema OS/2. &lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES"&gt;Un subsistema es una API completa que sirve
para que las aplicaciones escritas para tal subsistema se ejecuten en &amp;eacute;l, sean
independientes del n&amp;uacute;cleo y no puedan afectarlo en ninguna manera. Ved la
siguiente imagen de la Wikipedia y fijaros arriba a la derecha.&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES"&gt;&lt;a href="http://upload.wikimedia.org/wikipedia/commons/5/5d/Windows_2000_architecture.svg"&gt;&lt;span&gt;
 
 
  
  
  
  
  
  
  
  
  
  
  
  
 
 
 

 
 
&lt;/span&gt;&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES"&gt;&lt;a target="_blank" href="http://en.wikipedia.org/wiki/File:Windows_2000_architecture.svg"&gt;&amp;nbsp;&lt;/a&gt;&lt;/span&gt;&lt;a target="_blank" href="http://en.wikipedia.org/wiki/File:Windows_2000_architecture.svg"&gt;http://en.wikipedia.org/wiki/File:Windows_2000_architecture.svg&lt;/a&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;B&amp;aacute;sicamente esa deber&amp;iacute;a ser la arquitectura de
Windows. Fijaros tambi&amp;eacute;n en lo que hemos hablado antes sobre el HAL y el
Executive.&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES"&gt;&amp;iquest;Realmente Windows es as&amp;iacute;? Creo que no.
Te&amp;oacute;ricamente si cog&amp;eacute;is un programa 100% compatible POSIX y lo ejecut&amp;aacute;is en
Windows 2000, deber&amp;iacute;a funcionar. &amp;iquest;Lo hace? Pues no. En su momento lo prob&amp;eacute; y no
funcionaba. Tampoco lo hac&amp;iacute;a uno de OS/2 cuando ese subsistema estaba, todav&amp;iacute;a,
presente. No es que no funcionaran bien o hicieran alguna cosa rara, es que la
mayor&amp;iacute;a de veces simplemente no cargaban.&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES"&gt;&amp;iquest;Ha visto alguno de vosotros un Windows NT
ejecutado en un ARM o en un SuperH? Yo no y no creo que funcionen. &amp;iquest;Vais viendo
ya por d&amp;oacute;nde voy?&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES"&gt;Con esto no quiero decir que nunca hayan
llegado a funcionar, lo que quiero decir es que yo al menos no lo consegu&amp;iacute; en
su momento. En un MAC moderno podemos ejecutar pr&amp;aacute;cticamente cualquier comando
t&amp;iacute;pico UNIX, desde un &amp;ldquo;ls&amp;rdquo; hasta un &amp;ldquo;ps&amp;rdquo; pasando por un &amp;ldquo;dd&amp;rdquo; o lo que queramos.
Aparte de los que la propia Apple ha a&amp;ntilde;adido, que hay unos cuantos.&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES"&gt;De nuevo no me malinterpret&amp;eacute;is, en ning&amp;uacute;n
momento estoy diciendo que un MAC sea mejor que un Windows por eso. Simplemente
estoy diciendo que en un MAC s&amp;iacute; que est&amp;aacute;n separadas y presentes las distintas
piezas, o al menos as&amp;iacute; lo creo. De nuevo el tiempo me lo dir&amp;aacute;, y yo a vosotros.&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES"&gt;***&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES"&gt;Y ahora entramos de lleno en .NET. &amp;iquest;Por qu&amp;eacute;
.NET no es un subsistema y sin embargo est&amp;aacute; construido sobre Win32, que no es
precisamente un API limpia y ordenadita sino m&amp;aacute;s bien todo lo contrario? &amp;iquest;Por
qu&amp;eacute; no aprovecha Microsoft la arquitectura de los subsistemas para hacer a .NET
miembro de derecho propio dentro de Windows y no un mero envoltorio que cada
vez se va pareciendo m&amp;aacute;s a lo que envuelve, sobre todo en el tema de la &lt;i&gt;guarrer&amp;iacute;a&lt;/i&gt;?&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES"&gt;Si ya .NET es algo grande en el aspecto del
rendimiento y funcionalidad (comparado con su contrapartida Java y a veces con
el propio Win32), &amp;iquest;qu&amp;eacute; rendimiento no tendr&amp;iacute;a si fuera un subsistema
independiente?&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES"&gt;&amp;iquest;O es que toda la estructura arquitect&amp;oacute;nica de
Windows es una mentira como un castillo y no puede haber otros subsistemas
cooperando sobre el &lt;i&gt;ejecutivo&lt;/i&gt;? &lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES"&gt;Me gustar&amp;iacute;a que alguien me aclarara todo esto,
porque sinceramente no lo entiendo. Yo tengo mi teor&amp;iacute;a, que no voy a exponer
aqu&amp;iacute; no sea que se me acuse de lo que creo no soy, y menos ahora que tengo mi &lt;i&gt;calent&amp;oacute;n&lt;/i&gt; de fanboy&amp;hellip;&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=190697" 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/windows/default.aspx">windows</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/rationale/default.aspx">rationale</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/Win32/default.aspx">Win32</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/Windows+7/default.aspx">Windows 7</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/MAC/default.aspx">MAC</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/Apple/default.aspx">Apple</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/Interoperabilidad/default.aspx">Interoperabilidad</category></item><item><title>GetWindowText() en ropa interior</title><link>http://geeks.ms/blogs/rfog/archive/2011/01/18/getwindowtext-en-ropa-interior.aspx</link><pubDate>Tue, 18 Jan 2011 20:44:46 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:187570</guid><dc:creator>Rafael Ontivero</dc:creator><slash:comments>5</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/rfog/rsscomments.aspx?PostID=187570</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/rfog/commentapi.aspx?PostID=187570</wfw:comment><comments>http://geeks.ms/blogs/rfog/archive/2011/01/18/getwindowtext-en-ropa-interior.aspx#comments</comments><description>&lt;p align="justify"&gt;Justo he empezado a leer &lt;a href="http://www.amazon.com/gp/product/0321440307?ie=UTF8&amp;amp;tag=tholneth-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=0321440307"&gt;&lt;i&gt;The old new thing&lt;/i&gt;&lt;/a&gt; de Raymond Chen, que es un libro entresacado a partir de las entradas más interesantes del &lt;a href="http://blogs.msdn.com/b/oldnewthing/"&gt;blog del autor&lt;/a&gt;. Y me está gustando tanto que lo estoy leyendo como si fuera una novela de aventuras, sección tras sección. En él hay un curioso capítulo que trata de las interioridades de la función de Win32 &lt;a href="http://msdn.microsoft.com/en-us/library/ms633520(v=vs.85).aspx"&gt;&lt;i&gt;GetWindowText()&lt;/i&gt;&lt;/a&gt; que no he podido reprimirme en parafrasearlo aquí.&lt;/p&gt;  &lt;p align="justify"&gt;Para aquel que no lo sepa, dicha función devuelve en uno de sus parámetros el título de la ventana o el texto contenido en un control, dependiendo sobre qué tipo de ventana se ejecute.&lt;/p&gt;  &lt;p align="justify"&gt;Lo curioso es ver cómo funciona. Si la llamamos sobre una ventana de nuestro propio proceso, la función genera el mensaje WM_GETTEXT para que seamos nosotros mismos los que devolvamos el texto que queramos. Evidentemente si no capturamos el mensaje, será Windows quien devuelva el valor por defecto, que será el mismo que si se realiza la llamada a una ventana de otro proceso. En este caso, la función devolverá la cadena que Windows ha almacenado interiormente y que contendrá lo dicho.&lt;/p&gt;  &lt;p align="justify"&gt;Curioso, ¿no? De hecho en el libro de Raymod viene un ejemplo para hacer que una ventana devuelva un texto diferente según se llame desde el mismo proceso o fuera de él.&lt;/p&gt;  &lt;p align="justify"&gt;¿Por qué funciona esto así?&lt;/p&gt;  &lt;p align="justify"&gt;Según Chen es muy sencillo, y viene de la herencia de Windows 1.0 y versiones posteriores en las que la multitarea era cooperativa.&lt;/p&gt;  &lt;p align="justify"&gt;Imaginemos que vamos a mostrar la lista de programas en ejecución. Para ello, el programa enumerará todas las ventanas principales de Windows y les pedirá su nombre a través de &lt;i&gt;GetWindowText()&lt;/i&gt;. Ahora supongamos que uno de esos procesos está colgado por algún motivo. Si la función genera un WM_GETTEXT sobre dicho proceso tonto, Windows al completo se quedaría bloqueado porque al no procesar el mensaje, la función nunca retornaría y un supuesto programa “matador” de procesos que no responden también se colgaría…&lt;/p&gt;  &lt;p align="justify"&gt;Por lo tanto, los diseñadores de Windows decidieron que una llamada a &lt;i&gt;GetWindowText()&lt;/i&gt; debería comportarse tal y como se ha descrito más arriba. Es decir, si un proceso usa la función sobre sí mismo, es indicativo de que el bucle de mensajes está funcionando bien y por tanto podrá responder a un WM_GETTEXT. Pero si se hace desde otro proceso, nadie garantiza que el bucle de mensajes del llamado esté funcionando bien, por lo que entonces Windows toma el valor almacenado internamente, que generalmente es el nombre de la clase de ventana o el título de la misma.&lt;/p&gt;  &lt;p align="justify"&gt;De este modo, al menos desde Windows 95, un proceso tonto no tumba al sistema cuando intentemos matarlo desde el Administrador de Tareas o desde cualquier otro programa enumerador.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=187570" width="1" height="1"&gt;</description><category domain="http://geeks.ms/blogs/rfog/archive/tags/tips/default.aspx">tips</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/libros/default.aspx">libros</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/Win32/default.aspx">Win32</category></item><item><title>Hemos leído: Windows Internals 5ª Edición</title><link>http://geeks.ms/blogs/rfog/archive/2010/03/03/hemos-le-237-do-windows-internals-5-170-edici-243-n.aspx</link><pubDate>Wed, 03 Mar 2010 12:38:00 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:168613</guid><dc:creator>Rafael Ontivero</dc:creator><slash:comments>1</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/rfog/rsscomments.aspx?PostID=168613</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/rfog/commentapi.aspx?PostID=168613</wfw:comment><comments>http://geeks.ms/blogs/rfog/archive/2010/03/03/hemos-le-237-do-windows-internals-5-170-edici-243-n.aspx#comments</comments><description>&lt;p&gt;&lt;a target="_blank" href="http://www.microsoft.com/learning/en/us/book.aspx?ID=12069&amp;amp;locale=en-us"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;No s&amp;eacute; si es que la memoria me falla, o que tiempos antiguos fueron mejores o que simplemente he mezclado dos libros, pero lo cierto es que este libro me ha reportado m&amp;aacute;s desilusiones que ilusiones. Recuerdo haber le&amp;iacute;do ediciones anteriores (la cuarta seguro que no), aunque en mi biblioteca f&amp;iacute;sica &amp;ndash;la de los libros en papel, vamos-, s&amp;oacute;lo veo el de Helen Custer, que fue, si de nuevo las meninges no me enga&amp;ntilde;an, el primero o la precuela de la serie. Pero lo que no recuerdo es que fuera tan pol&amp;iacute;ticamente correcto, y eso es lo que me ha defraudado de este.&lt;/p&gt;
&lt;p&gt;Porque en el libro no viene nada que no est&amp;eacute; documentado en el DDK, el SDK u otra documentaci&amp;oacute;n emitida por Microsoft, lo &amp;uacute;nico es que, aqu&amp;iacute;, est&amp;aacute; todo reunido de una forma m&amp;aacute;s o menos coherente, organizada y en papel.&lt;/p&gt;
&lt;p&gt;Es evidente que intentar explicar en un libro &amp;ndash;aunque sea de m&amp;aacute;s de 1200 p&amp;aacute;ginas- el funcionamiento de un sistema operativo que tiene m&amp;aacute;s de cincuenta millones de l&amp;iacute;neas de c&amp;oacute;digo es tarea imposible. &lt;/p&gt;
&lt;p&gt;Lo que no esperaba es que fuera tan &lt;i&gt;pol&amp;iacute;ticamente correcto&lt;/i&gt;, tan formalmente estudiado para no resultar inadecuado, ya que seguro muchas de las cosas que se cuentan en &amp;eacute;l no son tal y como se han presentado, o se han omitido. Y estoy seguro de ello, porque en algunas secciones hay huecos y cosas que no est&amp;aacute;n del todo explicadas. Si bien se pueden deber al desconocimiento de los autores, o al recorte de p&amp;aacute;ginas, el texto podr&amp;iacute;a haber sido m&amp;aacute;s fluido. Hay secciones enteras que no son m&amp;aacute;s que un mero recitamiento en plan loro de lo aprendido, en lugar de resultar un continuo coherente. Y de hecho, hay partes que no las he le&amp;iacute;do por aburridas, pesadas y por apuntar a ser un mero listado de caracter&amp;iacute;sticas tal y como se pueden encontrar en una documentaci&amp;oacute;n oficial.&lt;/p&gt;
&lt;p&gt;Y como muestra de lo omitido, un bot&amp;oacute;n: &lt;i&gt;&lt;a href="http://geeks.ms/blogs/rfog/archive/2010/01/06/191-se-fragmenta-el-registro-de-windows.aspx"&gt;&amp;iquest;Se fragmenta el registro de Windows?,&lt;/a&gt;&lt;/i&gt; escrito en este mismo blog. Pues bien, hay muchas secciones as&amp;iacute;, que te dejan con la palabra en la boca, como si s&amp;oacute;lo te hubieran contado lo que han querido&amp;hellip;&lt;/p&gt;
&lt;p&gt;No obstante esas pegas, que pueden enteramente deberse a mi mismo y a que no aceptar&amp;iacute;a la invitaci&amp;oacute;n a un club que me aceptara como socio (parafraseando del mala manera al insigne Groucho), el libro debe ser una gozada para muchos administradores y algunos programadores, ya que te explica muchas cosas que de otro modo quedar&amp;iacute;an al aire o como interpretaci&amp;oacute;n de un curso de sistemas operativos 101.&lt;/p&gt;
&lt;p&gt;As&amp;iacute; mismo, en aquellos casos en los que pienses que el problema no est&amp;aacute; en tu c&amp;oacute;digo o tu script, puedes bucear dentro de las estructuras internas de Windows (all&amp;aacute; donde el libro las explica, que no es en muchos sitios, la verdad) para descubrir d&amp;oacute;nde te has equivocado tras muchas horas de investigar donde no era. &lt;/p&gt;
&lt;p&gt;Y poco m&amp;aacute;s que contar, si quieres ver qu&amp;eacute; trae el libro por dentro, pues te das un voltio por Amazon y miras el &amp;iacute;ndice.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=168613" 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/windows/default.aspx">windows</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/rationale/default.aspx">rationale</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/libros/default.aspx">libros</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/Win32/default.aspx">Win32</category></item><item><title>Conversión ANSI a Unicode y viceversa</title><link>http://geeks.ms/blogs/rfog/archive/2010/02/03/conversi-243-n-ansi-a-unicode-y-viceversa.aspx</link><pubDate>Wed, 03 Feb 2010 11:51:00 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:166165</guid><dc:creator>Rafael Ontivero</dc:creator><slash:comments>4</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/rfog/rsscomments.aspx?PostID=166165</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/rfog/commentapi.aspx?PostID=166165</wfw:comment><comments>http://geeks.ms/blogs/rfog/archive/2010/02/03/conversi-243-n-ansi-a-unicode-y-viceversa.aspx#comments</comments><description>&lt;p align="justify"&gt;Seguro que no es la primera vez que te pasa que te dejan una serie de rutinas (generalmente en formato DLL) que reciben cadenas en formato ANSI y tu aplicaci&amp;oacute;n est&amp;aacute; escrita en Unicode, y cuando preguntas si tienen versi&amp;oacute;n Unicode te responden que no y que no la van a tener&amp;hellip; Y como no quiero perder mi empleo, voy a parar aqu&amp;iacute;. &lt;/p&gt;
&lt;p align="justify"&gt;Pues bien, existe una forma muy sencilla de pasar cadenas entre ambos formatos sin tener que liarnos con las funciones de conversi&amp;oacute;n de Win32, que no son precisamente f&amp;aacute;ciles de manejar. Y como esto va a modo de receta, no entro en m&amp;aacute;s detalles.&lt;/p&gt;
&lt;p align="justify"&gt;Lo primero es incluir &lt;i&gt;atlconv.h&lt;/i&gt; en aquella unidad de compilaci&amp;oacute;n en donde vayamos a hacer conversiones.&lt;/p&gt;
&lt;p align="justify"&gt;Lo segundo es colocar la macro &lt;i&gt;USES_CONVERSION;&lt;/i&gt; dentro del m&amp;eacute;todo en el que vamos a realizar las conversiones.&lt;/p&gt;
&lt;p align="justify"&gt;Lo tercero es declarar un puntero ANSI o Unicode dependiendo de si queremos pasar de un lado a otro. &lt;/p&gt;
&lt;p align="justify"&gt;Y finalmente usar la macro adecuada. Ve&amp;aacute;moslo con un ejemplo:&lt;/p&gt;
&lt;pre&gt;#include &amp;lt;atlconv.h&amp;gt;

Void FuncionQueNecesitaPasarDeANSIaUnicode(void)
{
    USES_CONVERSION; //ANSI 2 UNICODE macros

    char szCad[MAX_PATH];
    LPWSTR szCadUnicode;
    FuncionQueNecesitaANSIporqueNoTieneUNICODE(szCad);
    szCadUnicode=A2W((LPCSTR)szCad);

    CString printCad;
    printCad.Format(_T(&amp;quot;ATPC: %s&amp;quot;),szCadUnicode);
    AddLogString(printCad);
}&lt;/pre&gt;
&lt;p align="justify"&gt;Hay una espuerta de macros con el formato&lt;/p&gt;
&lt;p align="justify"&gt;[C]&amp;lt;origen&amp;gt;2[C]&amp;lt;destino&amp;gt;[EX]();&lt;/p&gt;
&lt;p align="justify"&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES-TRAD"&gt;Origen y destino pueden ser A para ANSI,
W para Unicode, T para cuando estamos generando c&amp;oacute;digo agn&amp;oacute;stico en cuanto al
formato de cadena, y OLE para cadenas OLE. C se usa para cuando es una cadena
constante.&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES-TRAD"&gt;De este modo, A2W convertir&amp;aacute; de ANSI a
Unicode, y W2A al rev&amp;eacute;s. &lt;a href="http://msdn.microsoft.com/en-us/library/87zae4a3(VS.80).aspx"&gt;Aqu&amp;iacute;&lt;/a&gt; la
referencia completa.&lt;/span&gt;&lt;/p&gt;
&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=166165" width="1" height="1"&gt;</description><category domain="http://geeks.ms/blogs/rfog/archive/tags/c_2B002B00_/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/MFC/default.aspx">MFC</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/Win32/default.aspx">Win32</category></item><item><title>Todo lo que quisiste saber sobre las DLL y no te atreviste a preguntar (II)</title><link>http://geeks.ms/blogs/rfog/archive/2010/01/29/todo-lo-que-quisiste-saber-sobre-las-dll-y-no-te-atreviste-a-preguntar-ii.aspx</link><pubDate>Fri, 29 Jan 2010 11:28:00 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:166163</guid><dc:creator>Rafael Ontivero</dc:creator><slash:comments>3</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/rfog/rsscomments.aspx?PostID=166163</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/rfog/commentapi.aspx?PostID=166163</wfw:comment><comments>http://geeks.ms/blogs/rfog/archive/2010/01/29/todo-lo-que-quisiste-saber-sobre-las-dll-y-no-te-atreviste-a-preguntar-ii.aspx#comments</comments><description>&lt;p align="justify"&gt;Como pod&amp;eacute;is ver no se me ha &lt;a href="http://geeks.ms/blogs/rfog/archive/2009/06/29/todo-lo-que-quisiste-saber-sobre-las-dll-y-no-te-atreviste-a-preguntar-i.aspx"&gt;olvidado el tema&lt;/a&gt;, simplemente es que he estado demasiado gandulete como para escribir sobre esto, pero una pregunta en el &lt;a href="http://social.msdn.microsoft.com/Forums/es-ES/vcppes/thread/8539bf2a-8510-45fe-9319-d4906d5def27"&gt;foro web de C++&lt;/a&gt; me ha hecho que me ponga a ello. En teor&amp;iacute;a esta deber&amp;iacute;a ser la tercera parte en lugar de la segunda, aunque la verdad no es que realmente tenga mucha importancia. Por lo tanto, esta entrada que est&amp;aacute;s leyendo sigue a &lt;a href="http://geeks.ms/blogs/rfog/archive/2009/06/29/todo-lo-que-quisiste-saber-sobre-las-dll-y-no-te-atreviste-a-preguntar-i.aspx"&gt;esta&lt;/a&gt; otra.&lt;/p&gt;
&lt;p align="justify"&gt;Aqu&amp;iacute; voy a contar los tres modos que hay de usar una DLL desde C y C++, aunque solo voy a explicar dos de ellos porque el tercero digamos que viene de las primeras versiones de Windows y ni siquiera s&amp;eacute; si los compiladores modernos la soportan.&lt;/p&gt;
&lt;p align="justify"&gt;Pero antes, una introducci&amp;oacute;n.&lt;/p&gt;
&lt;p align="justify"&gt;&lt;strong&gt;&lt;span style="text-decoration:underline;"&gt;&amp;iquest;Qu&amp;eacute; necesito para usar una DLL de terceros?&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p align="justify"&gt;Cuando vamos a usar una DLL, ya sea nuestra o de terceros, se nos deben suministrar al menos tres archivos. El primero, que no nos har&amp;iacute;a falta para el segundo m&amp;eacute;todo, es un fichero cabecera conteniendo los prototipos de las exportaciones de la DLL, es decir, las firmas de las funciones y la declaraci&amp;oacute;n de los tipos contenidos.&lt;/p&gt;
&lt;p align="justify"&gt;En general, el formato de cada prototipo debe seguir de cerca el siguiente formato:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p align="justify"&gt;__declspec(dllexport) __stdcall int HazAlgo(int algo);&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p align="justify"&gt;O&lt;/p&gt;
&lt;blockquote&gt;
&lt;p align="justify"&gt;extern &amp;ldquo;C&amp;rdquo; __declspec(dllexport) int HazAlgo(int algo);&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p align="justify"&gt;La primera firma declara una funci&amp;oacute;n con formato de llamada est&amp;aacute;ndar (el &lt;i&gt;__stdcall&lt;/i&gt;) que pertenece a una DLL y que resulta exportado, es decir, que podemos usar. La segunda declara lo mismo pero con el protocolo de llamada de C, que tambi&amp;eacute;n podr&amp;iacute;amos haber puesto como &lt;i&gt;__cdecl&lt;/i&gt;. Del protocolo de llamada ya habl&amp;eacute; en la entrada anterior, y en general todos los compiladores de C y C++ deber&amp;iacute;an entender ambas declaraciones, y si no lo hacen seguro que tienen expresiones similares.&lt;/p&gt;
&lt;p align="justify"&gt;El segundo fichero es lo que se conoce como biblioteca de importaci&amp;oacute;n, que es un archivo con la extensi&amp;oacute;n .lib, con la diferencia de que, en este caso, en lugar de contener las propias funciones como en una biblioteca normal, lo que contiene son las firmas de las funciones exportadas y c&amp;oacute;mo est&amp;aacute;n relacionadas con la propia DLL.&lt;/p&gt;
&lt;p align="justify"&gt;En el mundo Windows existen dos formatos de ficheros .lib: el COFF, que es el que usa Microsoft y compiladores compatibles y el OMF, que es el que usan otros compiladores como el C++Builder. Generalmente todos los compiladores suelen venir con una herramienta de conversi&amp;oacute;n de formato.&lt;/p&gt;
&lt;p align="justify"&gt;Y finalmente necesitamos la DLL y todas sus dependencias si las hubiera.&lt;/p&gt;
&lt;p align="justify"&gt;En general muchas veces no es necesario recompilar el c&amp;oacute;digo de nuestra aplicaci&amp;oacute;n cada vez que se modifique la DLL si no hemos cambiado nada de la parte p&amp;uacute;blica. Creo que incluso si se a&amp;ntilde;aden funciones a la DLL tampoco es necesario recompilar siempre y cuando no se cambie ninguna declaraci&amp;oacute;n de las existentes y enlazadas.&lt;/p&gt;
&lt;p align="justify"&gt;&lt;strong&gt;&lt;span style="text-decoration:underline;"&gt;Primer m&amp;eacute;todo: el f&amp;aacute;cil&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p align="justify"&gt;El m&amp;eacute;todo m&amp;aacute;s sencillo para usar una DLL en nuestro c&amp;oacute;digo en C o C++ es a&amp;ntilde;adir la biblioteca de importaci&amp;oacute;n (el fichero .lib) a las dem&amp;aacute;s bibliotecas en nuestro proyecto, lo que se suele hacer en las opciones del enlazador.&lt;/p&gt;
&lt;p align="justify"&gt;Luego incluimos el fichero cabecera en donde nos haga falta y ya est&amp;aacute; todo hecho: tan s&amp;oacute;lo debemos llamar a las funciones de la DLL como si fueran funciones normales y corrientes.&lt;/p&gt;
&lt;p align="justify"&gt;Debemos tener en cuenta que si la DLL contiene clases o tipos no est&amp;aacute;ndar, quiz&amp;aacute;s el enlazador sea incapaz de encontrar los nombres porque cada compilador de C++ ofusca el nombre de las funciones de una manera diferente, y en ese caso s&amp;oacute;lo nos queda la opci&amp;oacute;n de o bien pedir una DLL compatible con nuestro compilador o bien hacer un &lt;i&gt;strip&lt;/i&gt; del fichero LIB, ver c&amp;oacute;mo se llaman en realidad las funciones, y hacernos nosotros mismos el fichero cabecera. No os lo recomiendo.&lt;/p&gt;
&lt;p align="justify"&gt;El &amp;uacute;ltimo paso es dejar la DLL en una ruta que nuestro programa sea capaz de encontrar, como el directorio donde se est&amp;aacute; ejecutando o en alg&amp;uacute;n camino disponible en el PATH.&lt;/p&gt;
&lt;p align="justify"&gt;&lt;strong&gt;&lt;span style="text-decoration:underline;"&gt;Segundo m&amp;eacute;todo: carga din&amp;aacute;mica&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p align="justify"&gt;No lo he dicho antes, pero cuando se usa el primer m&amp;eacute;todo, las DLL se cargan de forma autom&amp;aacute;tica a la vez que nuestra aplicaci&amp;oacute;n, y siguen en memoria hasta que salimos. &lt;/p&gt;
&lt;p align="justify"&gt;Existe una forma de carga manual un poco m&amp;aacute;s laboriosa, pero que nos permite cosas como la carga din&amp;aacute;mica de temas, de extensiones, de plugins o de diferentes versiones de una misma DLL. &lt;/p&gt;
&lt;p align="justify"&gt;Supongamos que tenemos una DLL con las cadenas para cada idioma. Cuando arranquemos nuestra aplicaci&amp;oacute;n miramos qu&amp;eacute; idioma est&amp;aacute; en la configuraci&amp;oacute;n y cargamos manualmente la DLL adecuada. Es lo que hace autom&amp;aacute;ticamente el sistema MUI de Windows y la internacionalizaci&amp;oacute;n en .NET y otros lenguajes. Pues de igual forma que se hace autom&amp;aacute;ticamente, se puede hacer manualmente.&lt;/p&gt;
&lt;p align="justify"&gt;Para este m&amp;eacute;todo s&amp;oacute;lo necesitamos la DLL en cuesti&amp;oacute;n y la lista de prototipos de funciones. Lo primero es hacernos un puntero a funci&amp;oacute;n de cada una de las funciones de la DLL:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p align="justify"&gt;int (__stdcall *pHazAlgo)(int);&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p align="justify"&gt;Luego llamamos a la funci&amp;oacute;n de Win32 &lt;i&gt;&lt;a target="_blank" href="http://msdn.microsoft.com/en-us/library/ms684175(VS.85).aspx"&gt;LoadLibrary()&lt;/a&gt;&lt;/i&gt; pas&amp;aacute;ndole la cadena en donde est&amp;aacute; la DLL que queramos cargar. La funci&amp;oacute;n nos devolver&amp;aacute; un HINSTANCE, que si todo ha ido bien ser&amp;aacute; diferente de NULL. Entonces, para cada una de las funciones de la DLL, la cargamos sobre nuestro puntero mediante &lt;i&gt;&lt;a target="_blank" href="http://msdn.microsoft.com/en-us/library/ms683212(VS.85).aspx"&gt;GetProcAddress()&lt;/a&gt;&lt;/i&gt; pas&amp;aacute;ndole el HINSTANCE y la cadena con el nombre de la funci&amp;oacute;n en la DLL:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p align="justify"&gt;pHazAlgo=GetProcAddress(hLib,&amp;rdquo;HazAlgo&amp;rdquo;);&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p align="justify"&gt;Ahora tendremos un puntero a funci&amp;oacute;n (que realmente es un doble puntero, porque ese puntero apunta a una tabla dentro de la DLL que a su vez apunta a la funci&amp;oacute;n real). Con ese puntero podemos llamar a la funci&amp;oacute;n sin problemas:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p align="justify"&gt;int respuesta=pHazAlgo(3);&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p align="justify"&gt;Quiz&amp;aacute;s tengas que hacer alg&amp;uacute;n tipo de moldeo en la llamada a &lt;i&gt;GetProcAddress()&lt;/i&gt;.&lt;/p&gt;
&lt;p align="justify"&gt;Cuando queramos descargar de memoria esta DLL, llamamos a &lt;i&gt;&lt;a target="_blank" href="http://msdn.microsoft.com/en-us/library/ms683152(VS.85).aspx"&gt;FreeLibrary()&lt;/a&gt;&lt;/i&gt; y ser&amp;aacute; descargada. Nuestros punteros seguir&amp;aacute;n asignados, pero apuntar&amp;aacute;n a ning&amp;uacute;n sitio, por lo que si volvemos a necesitar la DLL (u otra versi&amp;oacute;n de la misma) deberemos repetir el proceso.&lt;/p&gt;
&lt;p align="justify"&gt;&lt;strong&gt;&lt;span style="text-decoration:underline;"&gt;Tercer m&amp;eacute;todo: ordinales y ficheros DEF&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p align="justify"&gt;Este es el que no voy a explicar porque es muy antiguo y ni siquiera s&amp;eacute; si sigue siendo v&amp;aacute;lido. Antiguamente las funciones dentro de las DLL se guardaban numeradas. Es decir, en lugar de guardar una cadena con el nombre y un puntero a la relaci&amp;oacute;n relativa dentro del fichero en los metadatos de la DLL, se guardaba un array de punteros que apuntaba a cada una de las funciones. &lt;/p&gt;
&lt;p align="justify"&gt;Luego se ten&amp;iacute;a un fichero DEF que pon&amp;iacute;a el nombre de la funci&amp;oacute;n y el ordinal que ten&amp;iacute;a dentro de la DLL (la posici&amp;oacute;n dentro de ese array), de forma que cuando se compilaba un programa para una DLL de este tipo (usando el fichero DEF en lugar del LIB), se dejaba un array de punteros a funciones que el cargador pareaba con el de la DLL&amp;hellip; &lt;/p&gt;
&lt;p align="justify"&gt;Ya os pod&amp;eacute;is imaginar la que se pod&amp;iacute;a armar si por cualquier motivo ese orden era cambiado por el compilador. El que faltara un ordinal simplemente lanzaba un error, pero el que se cambiara uno por otro pod&amp;iacute;a terminar tumbando no solo nuestra aplicaci&amp;oacute;n, sino Windows al completo, ya que en aquella &amp;eacute;poca las DLL s&amp;oacute;lo se cargaban una vez y eran usadas y compartidas por todas las aplicaciones que la requer&amp;iacute;an, sistema operativo incluido.&lt;/p&gt;
&lt;p align="justify"&gt;Esto se hac&amp;iacute;a as&amp;iacute; porque con la velocidad de los procesadores de aquellos a&amp;ntilde;os, el tiempo para buscar la cadena con la funci&amp;oacute;n en los metadatos y parearla con el puntero correspondiente consum&amp;iacute;a una gran cantidad de tiempo, sobre todo si hab&amp;iacute;a muchas funciones dentro de una DLL, y en la forma de ordinales tan s&amp;oacute;lo hab&amp;iacute;a que copiar punteros en bucle.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=166163" width="1" height="1"&gt;</description><category domain="http://geeks.ms/blogs/rfog/archive/tags/c_2B002B00_/default.aspx">c++</category><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/windows/default.aspx">windows</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/Win32/default.aspx">Win32</category></item><item><title>Obtener el propio número de versión desde MFC y Win32 (y II)</title><link>http://geeks.ms/blogs/rfog/archive/2010/01/26/obtener-el-propio-n-250-mero-de-versi-243-n-desde-mfc-y-win32-y-ii.aspx</link><pubDate>Tue, 26 Jan 2010 12:30:41 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:165956</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=165956</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/rfog/commentapi.aspx?PostID=165956</wfw:comment><comments>http://geeks.ms/blogs/rfog/archive/2010/01/26/obtener-el-propio-n-250-mero-de-versi-243-n-desde-mfc-y-win32-y-ii.aspx#comments</comments><description>&lt;p&gt;Hace poco expliqué cómo &lt;a href="http://geeks.ms/blogs/rfog/archive/2009/12/03/obtener-tu-propia-versi-243-n.aspx"&gt;obtener el número de versión del propio ejecutable&lt;/a&gt; desde C++ Builder utilizando la VCL (su biblioteca de clases) y dejé como pendiente el obtenerla desde Win32 o MFC. Como lo he necesitado, he modificado el código y lo presento aquí:&lt;/p&gt;  &lt;pre&gt;TCHAR appName[MAX_PATH];
GetModuleFileName(AfxGetApp()-&amp;gt;m_hInstance,appName,MAX_PATH-1);
DWORD handle;
DWORD size = GetFileVersionInfoSize(appName, &amp;amp;handle);
if(size!=0)
{
    TCHAR *buffer = new TCHAR[size + 1];
    GetFileVersionInfo(appName, 0, size, buffer);
    VS_FIXEDFILEINFO *pFixedInfo;
    UINT uVersionLen;
    if (VerQueryValue(buffer, _T(&amp;quot;\\&amp;quot;), (void**) &amp;amp; pFixedInfo, (UINT*) &amp;amp; uVersionLen) != 0)
    {
        CString version;
        version.Format(_T(&amp;quot;%d.%d.%d.%d&amp;quot;),HIWORD(pFixedInfo-&amp;gt;dwFileVersionMS),LOWORD(pFixedInfo-&amp;gt;dwFileVersionMS),HIWORD(pFixedInfo-&amp;gt;dwFileVersionLS),LOWORD(pFixedInfo-&amp;gt;dwFileVersionLS));
        CString title;
        GetWindowText(title);
        CString newTitle;
        newTitle.Format(_T(&amp;quot;%s - V%s&amp;quot;),title,version);
        SetWindowText(newTitle);
    }
    delete[] buffer;
}&lt;/pre&gt;

&lt;p&gt;Si os fijáis, el código es muy similar al del otro post, tan sólo cambia la forma de usar las cadenas, en una mezcla de MFC y Win32.&lt;/p&gt;

&lt;p&gt;Para obtener la ruta del propio ejecutable, tenemos que hacer una llamada a la función de Win32 &lt;i&gt;GetModuleName()&lt;/i&gt; que, a través del HINSTANCE de la aplicación, rellenará una cadena con la ruta, devolviendo el tamaño ocupado. No deben preocuparnos los desbordamientos de buffer si pasamos el tamaño correcto de la cadena: la función truncará hasta el máximo.&lt;/p&gt;

&lt;p&gt;Los pasos siguientes son iguales, y lo que cambia, de nuevo, es el manejo de las cadenas y cómo las añadimos al título de la ventana.&lt;/p&gt;

&lt;p&gt;Para que este código funcione en Win32 puro, tan sólo hay que usar las cadenas de C (y &lt;i&gt;sprintf()&lt;/i&gt; y accesorias) o bien usar las cadenas de la biblioteca de C++, que es lo que recomendaría.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=165956" width="1" height="1"&gt;</description><category domain="http://geeks.ms/blogs/rfog/archive/tags/c_2B002B00_/default.aspx">c++</category><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/windows/default.aspx">windows</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><item><title>¿Se fragmenta el registro de Windows?</title><link>http://geeks.ms/blogs/rfog/archive/2010/01/06/191-se-fragmenta-el-registro-de-windows.aspx</link><pubDate>Wed, 06 Jan 2010 13:22:00 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:164145</guid><dc:creator>Rafael Ontivero</dc:creator><slash:comments>10</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/rfog/rsscomments.aspx?PostID=164145</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/rfog/commentapi.aspx?PostID=164145</wfw:comment><comments>http://geeks.ms/blogs/rfog/archive/2010/01/06/191-se-fragmenta-el-registro-de-windows.aspx#comments</comments><description>&lt;p align="justify"&gt;La respuesta corta es que s&amp;iacute;. La larga es que no mucho. Veamos.&lt;/p&gt;
&lt;p align="justify"&gt;Acabo de terminar de leer la parte del libro de &lt;i&gt;Windows Internals&lt;/i&gt; que se refiere al registro de Windows, y b&amp;aacute;sicamente me ha quedado un mal sabor de boca, cosa que a veces suele pasar con este tipo de libros &lt;i&gt;pol&amp;iacute;ticamente aprobados&lt;/i&gt;, y es que no deja nada claro si el registro se fragmenta o no.&lt;/p&gt;
&lt;p align="justify"&gt;En disco, el registro no es m&amp;aacute;s que una serie de ficheros repartidos a lo largo de varios lugares, ficheros que se corresponden con las diferentes ramas del mismo. La mayor ventaja de Vista y siguientes frente a XP es que ahora existe un juego de llamadas a funci&amp;oacute;n que realizar&amp;aacute;n operaciones transaccionales sobre el mismo. Es decir, igual que en las bases de datos &amp;ndash;y el registro no deja de ser una-, iniciamos una transacci&amp;oacute;n, realizamos una serie de acciones y si las completamos bien, cerramos dicha transacci&amp;oacute;n, y si no, la abortamos. Para los programas instaladores esta caracter&amp;iacute;stica es cojonuda, y a veces tambi&amp;eacute;n para los programas de usuario. Con s&amp;oacute;lo imaginarnos dejar el registro a medio actualizar a causa de un corte de corriente&amp;hellip;&lt;/p&gt;
&lt;p align="justify"&gt;Lo que s&amp;iacute; queda claro es que en memoria la fragmentaci&amp;oacute;n es m&amp;iacute;nima. Es decir, casi da igual el grado de fragmentaci&amp;oacute;n que haya en los archivos (los &lt;i&gt;hive&lt;/i&gt;, como los llaman), cuando estos son cargados a memoria mediante virtualizaci&amp;oacute;n de la misma, la posible fragmentaci&amp;oacute;n queda reducida al m&amp;iacute;nimo. Adem&amp;aacute;s, los valores m&amp;aacute;s com&amp;uacute;nmente accedidos quedan cacheados. Tambi&amp;eacute;n se mantienen listas y cach&amp;eacute;s de escritura, para minimizar la sobrecarga en el sistema, lo que a veces, ante un corte imprevisto de corriente, hace que no se graben dichas modificaciones, aunque Windows garantiza la no corrupci&amp;oacute;n de los &lt;i&gt;hives&lt;/i&gt; mediante un sistema de mapeados y de escrituras en ficheros dobles y triples (m&amp;aacute;s o menos lo mismo que hago yo con los &lt;i&gt;firmwares&lt;/i&gt; cuando los datos no deben corromperse ante un corte de luz &amp;ndash;en mi caso se trata de memorias flash y eeproms, pero la situaci&amp;oacute;n es la misma). La descarga a disco se hace cada cinco segundos, aunque podemos forzar nosotros una mediante la llamada a la funci&amp;oacute;n &lt;i&gt;RegFlushKey()&lt;/i&gt; que, pese a lo que diga la documentaci&amp;oacute;n, hace un volcado de todo lo pendiente, no solo de la &lt;i&gt;Key&lt;/i&gt; abierta.&lt;/p&gt;
&lt;p align="justify"&gt;Pero en disco la cosa no est&amp;aacute; tan clara, y los autores tampoco lo dicen expresamente, pero parece ser que s&amp;iacute;, que el registro se puede fragmentar.&lt;/p&gt;
&lt;p align="justify"&gt;El registro se guarda en disco en bloques de 4KB. Es decir, aunque necesitemos 1 byte, el &lt;i&gt;hive&lt;/i&gt; crecer&amp;aacute; en 4KB. Eso no quiere decir que hayamos desperdiciado el resto, que no va a ocurrir, ya que luego dicho bloque se ir&amp;aacute; rellenando conforme se vayan a&amp;ntilde;adiendo claves.&lt;/p&gt;
&lt;p align="justify"&gt;Ese es el primer nivel de indirecci&amp;oacute;n. Encima existe un nuevo nivel l&amp;oacute;gico, en el que el registro se distribuye en forma de listas sobre dichos bloques, y que realmente conforman la estructura que nosotros vemos. Digamos que este nivel consiste en una especie de mezcla de &amp;aacute;rbol y lista enlazada que se va distribuyendo a lo largo de los bloques en disco.&lt;/p&gt;
&lt;p align="justify"&gt;La combinaci&amp;oacute;n de ambas estructuras permite la fragmentaci&amp;oacute;n de forma muy f&amp;aacute;cil: tan solo hay que ir creando &amp;aacute;rboles y luego eliminando nodos y &amp;aacute;rboles anteriores. De hecho, en poco tiempo podr&amp;iacute;amos tener un buen nivel de fragmentaci&amp;oacute;n, sobre todo cuando hemos instalado y desinstalado un mont&amp;oacute;n de programas.&lt;/p&gt;
&lt;p align="justify"&gt;No obstante, Windows lucha contra esta fragmentaci&amp;oacute;n mediante la compactaci&amp;oacute;n de los espacios libres. Es decir, cuando en un bloque f&amp;iacute;sico hay huecos, estos ser&amp;aacute;n compactados para dejar el mayor espacio libre contiguo, para &amp;ndash;creo entender- volver a ser reutilizado.&lt;/p&gt;
&lt;p align="justify"&gt;No obstante, el bloque no ser&amp;aacute; liberado de disco hasta que no est&amp;eacute; completamente vac&amp;iacute;o, y s&amp;oacute;lo cuando est&amp;eacute; al final del fichero. Es aqu&amp;iacute; donde puede venir la fragmentaci&amp;oacute;n, ya que podr&amp;iacute;amos tener muchos bloques vac&amp;iacute;os por en medio y una jodida clave al final que nos impidiera la limpieza de un buen espacio en disco, ya que el algoritmo de desfragmentaci&amp;oacute;n no coloca los huecos al final, sino que simplemente los maximiza.&lt;/p&gt;
&lt;p align="justify"&gt;Y aqu&amp;iacute; es donde entra la estad&amp;iacute;stica. Estad&amp;iacute;sticamente hablando, siempre habr&amp;aacute; algo de fragmentaci&amp;oacute;n porque habr&amp;aacute; huecos intermedios, que ser&amp;aacute;n rellenados conforme se vayan necesitando, y en el peor de los casos el registro no decrecer&amp;aacute; en tama&amp;ntilde;o, pero tampoco crecer&amp;aacute; hasta que todos los huecos est&amp;eacute;n rellenos.&lt;/p&gt;
&lt;p align="justify"&gt;Lo que m&amp;aacute;s me jode de todo esto es que en el libro no est&amp;aacute; muy claramente contado, sino que el tema de la fragmentaci&amp;oacute;n se recorre de puntillas, como si fuera un pecado. Tan s&amp;oacute;lo se comentan, de pasada, dos funciones que podr&amp;iacute;an permitirnos compactarlo y quiz&amp;aacute;s decrecerlo: &lt;i&gt;RegSaveKey()&lt;/i&gt; y &lt;i&gt;RegReplaceKey()&lt;/i&gt;, que dice son usadas por Windows Backup.&lt;/p&gt;
&lt;p align="justify"&gt;Podr&amp;iacute;amos intentar jugar con dichas funciones para ver si conseguimos compactar nuestro registro pero, si&amp;eacute;ndoos sincero, no tengo ganas de trastear con algo que podr&amp;iacute;a dejar mi ordenador completamente inservible s&amp;oacute;lo por ganar unos cuantos megas de disco&amp;hellip;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=164145" 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/windows/default.aspx">windows</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/vista/default.aspx">vista</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/libros/default.aspx">libros</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/Win32/default.aspx">Win32</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/Windows+7/default.aspx">Windows 7</category></item><item><title>BingOS o cómo no reventar de impaciencia</title><link>http://geeks.ms/blogs/rfog/archive/2009/12/28/bingos-o-c-243-mo-no-reventar-de-impaciencia.aspx</link><pubDate>Mon, 28 Dec 2009 11:01:13 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:163751</guid><dc:creator>Rafael Ontivero</dc:creator><slash:comments>4</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/rfog/rsscomments.aspx?PostID=163751</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/rfog/commentapi.aspx?PostID=163751</wfw:comment><comments>http://geeks.ms/blogs/rfog/archive/2009/12/28/bingos-o-c-243-mo-no-reventar-de-impaciencia.aspx#comments</comments><description>&lt;p&gt;Ya es oficial. Ya no tengo que morderme los nudillos, ni ponerme esparadrapos en la boca, ni pisarme a mi mismo para evitar soltarlo: Microsoft ha lanzado un nuevo sistema operativo especialmente diseñado para los ultraligeros y toda su familia anexa, por lo que tampoco descarto ver lectores de libros-e con esta tecnología en sus tripas.&lt;/p&gt;  &lt;p&gt;Como está basado en Windows CE, el núcleo será igual de estable, y al ser una versión “destripada”, todavía más. Por ejemplo, yo una vez conseguí una imagen de CE de 4MB conteniendo la GUI completa (también IE) e ignorando muchas cosas accesorias.&lt;/p&gt;  &lt;p&gt;La ventaja evidente es que muchos de los programas existentes para CE (léase Windows Mobile) funcionarán sin modificar…&lt;/p&gt;  &lt;p&gt;Pero la cosa no termina ahí, sino que, como nos tiene habituados, MS sacará varias versiones, incluso una “Starter” que sólo podrá navegar por determinados sitios, así como otra con sólo la posibilidad de navegación.&lt;/p&gt;  &lt;p&gt;Parece ser que la idea es darle una buena coz a Google, y aunque MS sea un dinosaurio lento y torpón, si se decide a poner en marcha la máquina, saca ventaja a quien sea. El anuncio más o menos oficial, aquí: &lt;a href="http://www.ethek.com/bingos-el-nuevo-sistema-operativo-de-microsoft/"&gt;http://www.ethek.com/bingos-el-nuevo-sistema-operativo-de-microsoft/&lt;/a&gt;.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=163751" width="1" height="1"&gt;</description><category domain="http://geeks.ms/blogs/rfog/archive/tags/escariotrop_26002300_237_3B00_as+gimn_26002300_233_3B00_sicas/default.aspx">escariotrop&amp;#237;as gimn&amp;#233;sicas</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/UMPC/default.aspx">UMPC</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/Windows+CE/default.aspx">Windows CE</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/hardware/default.aspx">hardware</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/Win32/default.aspx">Win32</category></item><item><title>Obtener tu propia versión</title><link>http://geeks.ms/blogs/rfog/archive/2009/12/03/obtener-tu-propia-versi-243-n.aspx</link><pubDate>Thu, 03 Dec 2009 10:22:10 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:161847</guid><dc:creator>Rafael Ontivero</dc:creator><slash:comments>4</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/rfog/rsscomments.aspx?PostID=161847</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/rfog/commentapi.aspx?PostID=161847</wfw:comment><comments>http://geeks.ms/blogs/rfog/archive/2009/12/03/obtener-tu-propia-versi-243-n.aspx#comments</comments><description>&lt;p&gt;Muchos habréis observado que en las propiedades de un ejecutable o una DLL suelen aparecer, en la pestaña Detalles de las propiedades, una serie de nombres y de datos sobre la versión de dicho fichero.&lt;/p&gt;  &lt;p&gt;Eso se consigue embebiendo en el ejecutable un recurso de versión, que en Win32 se llama RCVERSION y que consta de una serie de cadenas y valores predefinidos que podemos rellenar a nuestro gusto.&lt;/p&gt;  &lt;p&gt;En las imágenes de abajo podemos ver un ejemplo añadido a un ejecutable, tanto desde C++ Builder como desde Visual C++.&lt;/p&gt;  &lt;p&gt;&lt;img style="border-bottom:0px;border-left:0px;display:inline;border-top:0px;border-right:0px;" title="image" border="0" alt="image" src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rfog/image_5F00_26D238F3.png" width="610" height="456" /&gt;&lt;/p&gt;  &lt;p&gt;&lt;img style="border-bottom:0px;border-left:0px;display:inline;border-top:0px;border-right:0px;" title="image" border="0" alt="image" src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rfog/image_5F00_042DFA78.png" width="511" height="535" /&gt;&amp;#160; &lt;/p&gt;  &lt;p&gt;Si os fijáis, ambas tienen más o menos los mismos elementos, pero en el caso del C++Builder existe la opción de incrementar el número de Build automáticamente. Hasta donde yo sé, eso no lo permite Visual C++ (quizás se haga en conjunción con un CVS o cuando haya uno compatible), y básicamente consiste en incrementar automáticamente el último numerito cada vez que compilemos algo. A lo largo de diferentes versiones del producto, este incremento se producía cuando se hacía un Build, un Make o incluso nunca (debido a un bug). En la versión 2010 se hace cada vez que compilemos algo.&lt;/p&gt;  &lt;p&gt;Bueno, una vez que hemos especificado nuestro recurso de versión, es tiempo de que podamos leerlo desde el propio ejecutable para poderlo poner, por ejemplo, en la pantalla de “Acerca”, en la de “Splash” o donde queramos. Si os dais cuenta, esos números suelen aparecer en muchas aplicaciones.&lt;/p&gt;  &lt;p&gt;El código es muy sencillo:&lt;/p&gt;  &lt;pre&gt;DWORD handle;
DWORD size = GetFileVersionInfoSize(Application-&amp;gt;ExeName.w_str(), &amp;amp;handle);
wchar_t *buffer = new wchar_t[size + 1];
GetFileVersionInfo(Application-&amp;gt;ExeName.w_str(), 0, size, buffer);
VS_FIXEDFILEINFO *pFixedInfo;
UINT uVersionLen;
if (VerQueryValue(buffer, L&amp;quot;\\&amp;quot;, (void**) &amp;amp; pFixedInfo, (UINT*) &amp;amp; uVersionLen) != 0)
{
    String version = L&amp;quot; &amp;quot; + String(HIWORD(pFixedInfo-&amp;gt;dwFileVersionMS)) + L&amp;quot;.&amp;quot; + String(LOWORD(pFixedInfo-&amp;gt;dwFileVersionMS)) + L&amp;quot;.&amp;quot; + String
    (HIWORD(pFixedInfo-&amp;gt;dwFileVersionLS)) + L&amp;quot;.&amp;quot; + String(LOWORD(pFixedInfo-&amp;gt;dwFileVersionLS));
    m_caption = Caption + version + L&amp;quot; - &amp;quot;;
    Caption = m_caption + m_document-&amp;gt;FileName;
}
delete[] buffer;&lt;/pre&gt;

&lt;p&gt;El ejemplo que he puesto es para C++ Builder Unicode, pero resulta trivial convertirlo a C ó C++ estándar. Tan sólo hay que cambiar el tipo de las cadenas por las adecuadas.&lt;/p&gt;

&lt;p&gt;Primero se hace una llamada a &lt;i&gt;GetFileVersionInfoSize()&lt;/i&gt; pasando la ruta de nuestro ejecutable y un DWORD que de nada sirve. Con el tamaño del recurso, llamamos a &lt;i&gt;GetFileVersionInfo()&lt;/i&gt; volviendo a pasar la ruta del ejecutable y un buffer con el tamaño adecuado.&lt;/p&gt;

&lt;p&gt;Después creamos un puntero a una estructura del tipo &lt;i&gt;VS_FIXEDFILEINFO&lt;/i&gt; y la pasamos a la función &lt;i&gt;VerQueryValue()&lt;/i&gt;, que también recibe el buffer original, qué parte del recurso queremos sacar (“\\”, es decir, la versión raíz –los recursos de versión se pueden embeber unos dentro de otros) y algún que otro valor más.&lt;/p&gt;

&lt;p&gt;Si esta función encuentra lo que le decimos, entonces podemos usar el puntero de la estructura y formatear una cadena con los cuatro números de versión.&lt;/p&gt;

&lt;p&gt;Lo que hagamos con esa cadena es cosa nuestra. En este caso la añadimos al título de la ventana actual y lo guardamos en una variable miembro que usaremos cada vez que cambiemos de documento.&lt;/p&gt;

&lt;p&gt;Y no nos olvidemos de liberar la cadena asignada.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=161847" width="1" height="1"&gt;</description><category domain="http://geeks.ms/blogs/rfog/archive/tags/c_2B002B00_/default.aspx">c++</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/Win32/default.aspx">Win32</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/C_2B002B00_+Builder/default.aspx">C++ Builder</category></item><item><title>Cómo salta Windows entre anillos (Modo Kernel y modo Usuario)</title><link>http://geeks.ms/blogs/rfog/archive/2009/11/21/c-243-mo-salta-windows-entre-anillos-modo-kernel-y-modo-usuario.aspx</link><pubDate>Sat, 21 Nov 2009 13:37:03 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:160981</guid><dc:creator>Rafael Ontivero</dc:creator><slash:comments>5</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/rfog/rsscomments.aspx?PostID=160981</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/rfog/commentapi.aspx?PostID=160981</wfw:comment><comments>http://geeks.ms/blogs/rfog/archive/2009/11/21/c-243-mo-salta-windows-entre-anillos-modo-kernel-y-modo-usuario.aspx#comments</comments><description>&lt;p align="justify"&gt;Esta semana estamos de fiesta, y es que una de mis pasiones en el desarrollo siempre ha sido verle las tripas a Windows, y a ello vamos. Antes de nada, lo que voy a contar aquí es un resumen del punto &lt;i&gt;System Service Dispatching&lt;/i&gt; del capítulo 3 de &lt;i&gt;Windows Internals &lt;/i&gt;5ª edición, pero es un resumen un poco &lt;i&gt;especial&lt;/i&gt; porque voy a añadir cosas de mi cosecha, como siempre hago, ya que no es cosa de ir parafraseando lo que voy aprendiendo/recordando.&lt;/p&gt;  &lt;p align="justify"&gt;En entradas anteriores, y algunas veces en los foros, he comentado sobre &lt;i&gt;saltos entre anillo 0 y anillo 3&lt;/i&gt;, y aquí voy a explicar de pasada lo que significa. Un microprocesador moderno (y no tan moderno), cuenta con un juego de instrucciones en cierta medida especiales, instrucciones que son necesarias para configurar el hardware y el propio funcionamiento del software. Hablamos aquí de las interrupciones y toda su parafernalia asociada, del control de la memoria virtual, del acceso directo a hardware (es decir, escribir o leer en una dirección de memoria o en un puerto en el que no hay tal, sino alguna electrónica que debe reaccionar en base a dicha lectura o escritura), etc.&lt;/p&gt;  &lt;p align="justify"&gt;Esas instrucciones son peligrosas de usar, y en general no deben estar disponibles para los programas normales, ya que entonces un error podría llevar a la caída total del sistema o incluso a la rotura de algún elemento electrónico.&lt;/p&gt;  &lt;p align="justify"&gt;Es decir, que podríamos dividir el juego de instrucciones de un microprocesador en dos grandes grupos: aquellas que no son necesarias para que un programa funcione normalmente y las que, si se usan de forma incorrecta, pueden terminar armando un buen pirifostio.&lt;/p&gt;  &lt;p align="justify"&gt;Pues básicamente eso son los anillos 0 y 3. En el 0 están las instrucciones peligrosas, en el 3 las que cualquier programa puede usar, y si un programa normal utiliza una del cero, generará una excepción (¿De qué me sonará esto?) que será capturada por el sistema operativo y manejada a su antojo. Aunque realmente no es del todo así, para nuestro propósito es suficiente. &lt;/p&gt;  &lt;p align="justify"&gt;(Si os dais cuenta, he hablado del 0 y del 3, pero también hay un 1 y un 2, que Windows no utiliza. Digamos que la separación de las instrucciones en estos distintos niveles permiten una serie de facilidades a la hora de construir software de sistemas, ya sean sistemas operativos o aplicaciones que vayan a correr en un microprocesador con estas características, lo que ocurre es que Windows aprovecha estos niveles únicamente de una sola forma, que llama modo usuario y modo kernel).&lt;/p&gt;  &lt;p align="justify"&gt;Pues bien, el &lt;i&gt;kelmer&lt;/i&gt;, uis, perdón, el kernel, la mayoría de los drivers, y el motor gráfico (que fue ampliamente criticado en su momento pero que permitió que NT 4.0 pudiera ser usado en ordenadores no tan potentes) se ejecutan en el anillo 0, y los demás subsistemas (incluido Win32) en el 3. De esta forma un programador chapucero (o un compilador) sólo podrá tumbar su programa y nada más. Recordemos los días de Windows 3.x y DOS en los cuales tumbar por completo el sistema era tan fácil como ejecutar dos instrucciones de ensamblador seguidas: cli y luego sti, o al revés, ya no me acuerdo.&lt;/p&gt;  &lt;p align="justify"&gt;Una aplicación llama a una función, que debe terminar siendo ejecutada dentro del kernel (por ejemplo, abrir y leer de un fichero, cosa que necesita que los drivers de disco hagan trabajo de bajo nivel sobre la controladora y sobre el propio disco). Pongamos que nuestro programa llama a &lt;i&gt;WriteFile()&lt;/i&gt;, y nos da igual que sea una aplicación .NET llamando a sus clases, ya que terminará en esa función. Esa función, que está en Kernel32.dll y pertenece al subsistema Win32, llamará a NtWriteFile(), que está en Ntdll.dll y no pertenece a ningún subsistema, sino que está disponible para cualquiera de ellos. Esta función llamará entonces a KiSystemService(), que está en Ntoskrnl.exe y se ejecuta en el anillo 0 en lugar del 3. Finalmente, esta última función hará lo que tenga que hacer llamando a otras funciones del kernel y de los drivers hasta que al final devolverá el resultado hacia atrás hasta nuestra aplicación.&lt;/p&gt;  &lt;p align="justify"&gt;Fácil, ¿no? Pues no, porque si nuestra aplicación hubiera llamado a WriteFile() con algún parámetro mal que fuera crítico (y se me ocurre pasar un valor aleatorio diferente de cero al handle del fichero sobre el que queremos escribir), lo más seguro es que termináramos en una pantalla azul (como más o menos ocurría en Windows 3.x y a veces en Windows 9x). Además, es muy posible que durante el procesamiento de la función, se salte varias veces entre el modo kernel y el user por necesidades del guión.&lt;/p&gt;  &lt;p align="justify"&gt;Pero todavía hay más, ya que no hemos tenido en cuenta que el controlador de tiempos y de procesos puede cortar en cualquier momento esa llamada para atender otros procesos o incluso hilos de nuestra aplicación. Vamos, que no es fácil ni de lejos.&lt;/p&gt;  &lt;p align="justify"&gt;¿Cómo se produce el salto entre el anillo 3 y el 0, que hemos descrito más arriba? Pues depende del procesador que estemos usando. En la época de Windows 9x (y de la parte en modo protegido de Windows 3.x cuando la había), y para micros antiguos, NtWriteFile(), después de verificar que los parámetros recibidos son correctos, coloca en varios registros del procesador lo necesario, y ejecuta la instrucción &lt;i&gt;int 0x2e&lt;/i&gt;, que genera una excepción si se hace desde el anillo 3. Esta excepción es recogida por el Kernel, que mediante los parámetros que hay en los registros determina si es una petición válida (y si no lo es protestará) y la procesará mediante la ejecución de la función correspondiente situada en un array de punteros a función que se llama &lt;i&gt;System Service Dispatch Table&lt;/i&gt;, de las que creo que hay varias. Básicamente, lo que está haciendo es recibir un índice que se corresponde a una posición dentro del array de punteros, y como nos equivoquemos con esto la hemos cagado a base de bien, y es por eso por lo que antes del salto entre anillos se verifican los parámetros. El retorno al anillo 3 se produce con la ejecución de la instrucción &lt;i&gt;iretd.&lt;/i&gt;&lt;/p&gt;  &lt;p align="justify"&gt;En micros Intel más modernos, el salto se hace mediante la instrucción &lt;i&gt;sysenter&lt;/i&gt; y la vuelta mediante &lt;i&gt;sysexit&lt;/i&gt; (o &lt;i&gt;iret&lt;/i&gt; si estamos en modo depuración). En un AMD las instrucciones son &lt;i&gt;syscall&lt;/i&gt; y &lt;i&gt;sysret&lt;/i&gt;.&lt;/p&gt;  &lt;p align="justify"&gt;Y finalmente, en micros de 64 bits con la arquitectura x64 las instrucciones son las mismas que en el AMD (por que fueron los primeros en implementarla) y en la I64, &lt;i&gt;epc&lt;/i&gt;.&lt;/p&gt;  &lt;p align="justify"&gt;Si os dais cuenta, dependiendo del microprocesador se hace de una u otra forma, lo que puede ser un serio quebradero de cabeza. Lo que hace Windows al arrancar un sistema de 32 bits es instalar la instrucción correcta en una posición de memoria y juego ejecutar sobre ella, con lo que a lo anterior añadimos un nuevo nivel de indirección. &lt;/p&gt;  &lt;p align="justify"&gt;La secuencia completa de paso del anillo 3 al 0 consiste, más o menos, en lo siguiente: primero se verifican los parámetros recibidos de la forma más completa posible, luego se ejecuta la instrucción que hay en cierta posición de memoria, que a su vez generará una excepción, que será controlada por el sistema operativo, que mirará si los parámetros son correctos, y si lo son volverá a saltar sobre un puntero a puntero a función, y finalmente lo que haya allí hará el trabajo. &lt;/p&gt;  &lt;p align="justify"&gt;Eso para un solo salto. Imaginaros cuántos son necesarios para que nuestro programa, y el sistema operativo funcione. Y no hemos hablado de que en cada una de esos pasos es necesario que la pila se guarde o se recupere, y que los datos deben ser copiados desde la pila de modo user a la de modo kernel para evitar que la aplicación pueda modificarlos en medio de una operación interna…&lt;/p&gt;  &lt;p align="justify"&gt;En un sistema x64 la operación es algo más sencilla porque la instrucción de salto es siempre la misma y no es necesaria la indirección extra sobre la instrucción ya que da igual que el microprocesador sea un Intel o un AMD.&lt;/p&gt;  &lt;p align="justify"&gt;Esto quizás te presente una duda en el caso de equipos de 32 bits: ¿por qué no está cableada dicha instrucción y simplemente a la hora de instalar Windows o de arrancarlo, el cargador pone en memoria el juego de DLLs correcto? Pues realmente no tengo ni idea, lo que sí tengo claro es que en ese caso Windows debería contar con al menos 4 juegos completos de DLLs y o bien elegir el necesario durante la instalación o casi cuadriplicar el espacio ocupado en disco. Lo que sí es cierto es que si se hubiera hecho así, el Windows de 32 bits funcionaría sensiblemente más rápido… o no.&lt;/p&gt;  &lt;p align="justify"&gt;Sólo nos queda ver, por mor de completitud, cómo funciona internamente el kernel sobre sí mismo. Supongamos por un momento que el kernel necesita acceder a la funcionalidad que hay en WriteFile(), pero en lugar de llamar a esta función directamente, lo que hace es llamar directamente a la rutina a la que se está apuntando en la tabla SSDT y santas pascuas, ya que en principio no se necesita verificar los parámetros que se suponen son correctos, y aparte de eso ya estamos en el anillo 0. No obstante, un driver no puede hacerlo así porque Microsoft no se fía de ellos, y es por ello que existen unas funciones que tiene como prefijo Zw y que son las que llamarán a su homónimo apuntado por la SSDT después de realizar las verificaciones –menos que si se llamara desde el anillo 3- oportunas.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=160981" width="1" height="1"&gt;</description><category domain="http://geeks.ms/blogs/rfog/archive/tags/windows/default.aspx">windows</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/vista/default.aspx">vista</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/hardware/default.aspx">hardware</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/libros/default.aspx">libros</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/Win32/default.aspx">Win32</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/Windows+7/default.aspx">Windows 7</category></item><item><title>Eligiendo qué hacer cuando pete nuestra aplicación</title><link>http://geeks.ms/blogs/rfog/archive/2009/11/19/eligiendo-qu-233-hacer-cuando-pete-nuestra-aplicaci-243-n.aspx</link><pubDate>Thu, 19 Nov 2009 17:53:00 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:160861</guid><dc:creator>Rafael Ontivero</dc:creator><slash:comments>3</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/rfog/rsscomments.aspx?PostID=160861</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/rfog/commentapi.aspx?PostID=160861</wfw:comment><comments>http://geeks.ms/blogs/rfog/archive/2009/11/19/eligiendo-qu-233-hacer-cuando-pete-nuestra-aplicaci-243-n.aspx#comments</comments><description>&lt;p align="justify"&gt;En la &lt;a href="http://geeks.ms/blogs/rfog/archive/2009/11/18/de-excepciones-del-depurador-de-windows-y-de-visual-studio.aspx"&gt;entrada anterior&lt;/a&gt; expliqu&amp;eacute; qu&amp;eacute; ocurre cuando una aplicaci&amp;oacute;n peta y se genera una excepci&amp;oacute;n no controlada (o controlada pero relanzada), y en esta voy a explicar c&amp;oacute;mo podemos, desde nuestro propio programa, configurar el modo en que eso ocurre. Pero antes una introducci&amp;oacute;n.&lt;/p&gt;
&lt;p align="justify"&gt;En algunos lados he dicho que las excepciones son caras. Con eso no me refiero a que cuesten dinero, sino a que es un tipo de caracter&amp;iacute;stica que resulta muy complicada de procesar y que a veces requiere de bastante tiempo de proceso. Cuando se dispara una interrupci&amp;oacute;n en una aplicaci&amp;oacute;n, sobre todo si ocurre en el lado del kernel, &amp;eacute;ste tiene que entrar y salir varias veces entre su modo y el de usuario, operaciones que no son baratas (de nuevo no en dinero, aunque lo mismo en su servidor en producci&amp;oacute;n s&amp;iacute;) ya que significan saltar entre los anillos 0 y 3 del procesador. Aparte de eso, se debe recorrer la pila (a ambos lados de los anillos) para ir buscando el controlador adecuado, ejecutarlo y en la mayor&amp;iacute;a de casos continuar con la b&amp;uacute;squeda. &lt;/p&gt;
&lt;p align="justify"&gt;Cuando ponemos un bloque try/catch, o __try/__except &amp;oacute; __try/__finally, el compilador deja &amp;ldquo;marcas&amp;rdquo; en la pila, &amp;ldquo;marcas&amp;rdquo; que ser&amp;aacute;n le&amp;iacute;das por el controlador de excepciones. Dependiendo de c&amp;oacute;mo lo hayamos hecho, y el n&amp;uacute;mero de bloques y de controladores, el sistema tendr&amp;aacute; que salvar y restaurar el estado de la pila y de la aplicaci&amp;oacute;n para ir ejecutando los diferentes bloques de captura, y a veces incluso se necesita de cierta &amp;ldquo;inteligencia&amp;rdquo; para que la ejecuci&amp;oacute;n sea la correcta. El tema queda bastante claro una vez que se han le&amp;iacute;do los cap&amp;iacute;tulos de los dos libros que mencion&amp;eacute;, con una excepci&amp;oacute;n: que esos recorridos requieren tiempo, sobre todo si hay saltos entre anillo 0 y 3, por lo que en general el uso de excepciones est&amp;aacute; para eso: para ser usadas cuando realmente se produzca una, y no alegremente como una mera caracter&amp;iacute;stica de nuestro lenguaje.&lt;/p&gt;
&lt;p align="justify"&gt;Dicho esto, considero que el ejemplo que Jeffrey Ritcher pone al final del cap&amp;iacute;tulo 25 no es muy correcto, no porque est&amp;eacute; mal, sino porque realizar gesti&amp;oacute;n de memoria mediante excepciones me parece que es matar moscas a ca&amp;ntilde;onazos&amp;hellip; aparte del desperdicio de la misma. Ritcher crea una hoja de c&amp;aacute;lculo de un tama&amp;ntilde;o predefinido pero sin asignar ning&amp;uacute;n tipo de memoria. Luego, ante cada requerimiento de que una celda sea llenada con algo, intenta escribir en la posici&amp;oacute;n. Si ya hay memoria asignada todo ir&amp;aacute; bien, pero si no, se disparar&amp;aacute; una excepci&amp;oacute;n que asignar&amp;aacute; un bloque a dicha celda. La barbaridad est&amp;aacute; en que cada asignaci&amp;oacute;n, aunque sea de un solo byte, asignar&amp;aacute; 4KB (que es el tama&amp;ntilde;o de p&amp;aacute;gina de RAM), y en que el gasto de la excepci&amp;oacute;n y su control es enormemente m&amp;aacute;s caro que simplemente comprobar si la memoria est&amp;aacute; asignada o no. A no ser que se me escape algo, como ejemplo sobre el funcionamiento de las excepciones, vale, pero como ejemplo de algoritmo gen&amp;eacute;rico, no.&lt;/p&gt;
&lt;p align="justify"&gt;De todos modos, el sistema de excepciones es my potente y vers&amp;aacute;til, y con la combinaci&amp;oacute;n del registro, podemos configurar a base de bien el comportamiento de las no controladas. &lt;i&gt;Windows Internals&lt;/i&gt; lista 25 claves para cambiar el comportamiento, alguna de ellas tan radicales como hacer que ni siquiera se ejecute &lt;i&gt;WerFault.exe&lt;/i&gt; y nuestra aplicaci&amp;oacute;n desaparezca de forma silenciosa.&lt;/p&gt;
&lt;p align="justify"&gt;Pero como dir&amp;iacute;a el personaje de los dibujos animados, &lt;i&gt;no se vayan todav&amp;iacute;a, que hay m&amp;aacute;s&lt;/i&gt;. Aparte de poder instalar y controlar ciertas funciones de control de excepciones, podemos configurar el modo con que nuestra aplicaci&amp;oacute;n se comunica con el gestor de las mismas. Es decir, mediante ciertas llamadas a funciones de Win32, podemos decirle al sistema &lt;i&gt;WER&lt;/i&gt; c&amp;oacute;mo debe comportarse, qu&amp;eacute; ficheros adjuntar, etc.&lt;/p&gt;
&lt;p align="justify"&gt;La mayor&amp;iacute;a de las funciones que voy a citar aqu&amp;iacute; de pasada, se encuentran dentro de &lt;i&gt;kernel32.dll&lt;/i&gt; y para usarlas debemos incluir &lt;i&gt;werapi.h.&lt;/i&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;div align="justify"&gt;&lt;i&gt;WerSetFlags()/WerGetFlags()&lt;/i&gt;. Cambiamos o leemos si queremos que se incluya el &lt;i&gt;heap&lt;/i&gt; (mont&amp;iacute;culo) en el informe, si se suspender&amp;aacute;n todos los hilos o s&amp;oacute;lo el que fall&amp;oacute;, si se a&amp;ntilde;adir&amp;aacute; el informe a la lista de errores, y si se enviar&amp;aacute; o no a Microsoft. &lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;div align="justify"&gt;&lt;i&gt;WerAddExcludedApplication()/WerRemoveExcludedApplication()&lt;/i&gt;. A&amp;ntilde;adir o eliminar una aplicaci&amp;oacute;n a la lista de aplicaciones excluidas de la generaci&amp;oacute;n de informes.&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;div align="justify"&gt;&lt;i&gt;WerRegisterFile()/WerUnregisterFile()&lt;/i&gt;. A&amp;ntilde;adir o quitar el fichero indicado al informe.&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;div align="justify"&gt;&lt;i&gt;WerRegisterMemoryBlock()/WerUnregisterMemoryBlock()&lt;/i&gt;.&lt;i&gt; &lt;/i&gt;A&amp;ntilde;adir/Qutar un volcado de un &amp;aacute;rea de la memoria de nuestro programa.&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p align="justify"&gt;Tambi&amp;eacute;n podemos crear un informe desde nuestro programa cuando queramos. Los pasos a seguir son:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;div align="justify"&gt;Llamar a &lt;i&gt;WerReportCreate()&lt;/i&gt;, que inicia el informe.&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;div align="justify"&gt;Llamar tantas veces a &lt;i&gt;WerReportSetParameter()&lt;/i&gt; como par&amp;aacute;metros queramos cambiar.&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;div align="justify"&gt;Llamar tantas veces a &lt;i&gt;WerReportAddDump()&lt;/i&gt; como bloques de memoria queramos incluir.&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;div align="justify"&gt;Llamar tantas veces a &lt;i&gt;WerReportAddFile()&lt;/i&gt; como ficheros del tipo que sean queramos incluir.&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;div align="justify"&gt;Llamar a &lt;i&gt;WerReportSetUIString()&lt;/i&gt; para a&amp;ntilde;adir opciones a la pantalla de WerFault.exe.&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;div align="justify"&gt;Llamar a &lt;i&gt;WerReportSubmit()&lt;/i&gt;, que dependiendo de la configuraci&amp;oacute;n para el programa y/o gen&amp;eacute;ricas que se tengan, enviar&amp;aacute; o no, preguntar&amp;aacute; o no, etc. qu&amp;eacute; hacer con el informe.&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;div align="justify"&gt;Llamar a &lt;i&gt;WerReportCloseHandle() &lt;/i&gt;para terminar con el tema.&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p align="justify"&gt;Como pod&amp;eacute;is ver, la cosa es muy potente, y puede ser enormemente &amp;uacute;til en determinadas situaciones. Imaginemos que nuestra aplicaci&amp;oacute;n est&amp;eacute; petando en casa del cliente y no haya modo de ver qu&amp;eacute; pu&amp;ntilde;etas pasa. La generaci&amp;oacute;n de informes a demanda podr&amp;iacute;a ser la soluci&amp;oacute;n. Lo que no he visto es c&amp;oacute;mo recibir e interpretar esos informes.&lt;/p&gt;
&lt;p align="justify"&gt;Tambi&amp;eacute;n podemos usar estas funciones cuando sea nuestra aplicaci&amp;oacute;n la que est&amp;eacute; controlando la excepci&amp;oacute;n, pero debemos ser cuidadosos ya que &amp;eacute;sta podr&amp;iacute;a estar tan estropeada que el uso de todo esto volviera a genera nuevas excepciones que terminaran en el mismo c&amp;oacute;digo, que a su vez generara otras que&amp;hellip;&lt;/p&gt;
&lt;p align="justify"&gt;Se supone que Windows es lo suficientemente inteligente como para detener la cadena, pero como yo ya he visto m&amp;aacute;s de una vez petar de forma continua a una aplicaci&amp;oacute;n en Windows Vista hasta que la he matado desde el administrador de tareas, debemos ser cuidadosos con su uso.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=160861" width="1" height="1"&gt;</description><category domain="http://geeks.ms/blogs/rfog/archive/tags/c_2B002B00_/default.aspx">c++</category><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/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/vista/default.aspx">vista</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/hardware/default.aspx">hardware</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/libros/default.aspx">libros</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><category domain="http://geeks.ms/blogs/rfog/archive/tags/Windows+7/default.aspx">Windows 7</category></item><item><title>De excepciones, del depurador, de Windows y de Visual Studio</title><link>http://geeks.ms/blogs/rfog/archive/2009/11/18/de-excepciones-del-depurador-de-windows-y-de-visual-studio.aspx</link><pubDate>Wed, 18 Nov 2009 16:54:09 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:160776</guid><dc:creator>Rafael Ontivero</dc:creator><slash:comments>1</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/rfog/rsscomments.aspx?PostID=160776</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/rfog/commentapi.aspx?PostID=160776</wfw:comment><comments>http://geeks.ms/blogs/rfog/archive/2009/11/18/de-excepciones-del-depurador-de-windows-y-de-visual-studio.aspx#comments</comments><description>&lt;p align="justify"&gt;Esto leyendo la quinta edición de &lt;i&gt;&lt;a href="http://www.microsoft.com/learning/en/us/Book.aspx?ID=12069&amp;amp;locale=en-us"&gt;Windows Internals,&lt;/a&gt;&lt;/i&gt; que cubre Windows Vista y Windows Server 2008 y es la última versión disponible del libro. Allá por los años del Windows 95 y del NT 4.0, un poco antes, un poco después, estaba yo muy interesado en las tripillas de los sistemas operativos, y aparte de empacharme con algún que otro mamotreto genérico sobre el tema, le di caña a los equivalentes, como &lt;i&gt;Windows 95, al descubierto&lt;/i&gt;, o el &lt;i&gt;Windows NT&lt;/i&gt; de Helen Custer, así como otros de similar temática. Vamos, que prácticamente me leí todo lo que pude conseguir sobre las interioridades de esos sistemas operativos.&lt;/p&gt;  &lt;p align="justify"&gt;Pero desde hace un tiempo me veo en la tesitura de que, conversando aquí y allí, me he dado cuenta de que me he quedado bastante obsoleto en el tema, con cosas que no sólo han sido mejoradas, sino que ahora funcionan de forma completamente diferente, así que me he puesto las pilas y le estoy dando un buen repaso al libro…&lt;/p&gt;  &lt;p align="justify"&gt;Bueno, pues como iba diciendo, el capítulo 3 del citado no es que sea nada del otro mundo. Bueno, sí, lo cierto es que como no sepas de programación de hardware y hayas hecho algo, te vas a quedar poco menos que a dos velas con muchas de las cosas que aparecen, ya que tienen que ver con la gestión de interrupciones, tanto de software como de hardware, así como las excepciones y demás intríngulis que todo sistema operativo ha de cumplir. &lt;/p&gt;  &lt;p align="justify"&gt;Personalmente yo he hecho un par de proyectos basados en un microprocesador, aunque generalmente, cuando lo hago, suelo trastear con microcontroladores más o menos potentes, y la verdad es que muchas de las cosas que aparecen ahí explicadas, con la evidente diferencia entre un sistema operativo como es Windows y lo que un mindundi como yo haya podido hacer, me las he encontrado en mis desarrollos. Tener en cuenta las prioridades y los niveles de las interrupciones, programarlos y cambiarlos en tiempo real, instalar y quitar vectores de interrupción, etc.&lt;/p&gt;  &lt;p align="justify"&gt;Por lo menos eso es de lo que trata la parte del capítulo 3 que he leído, que ciertamente me parece demasiado detallista en cosas que, la verdad, a no ser que vayas a meterte de lleno en la creación de drivers primarios para Windows, de poco te sirve. Y si sabes de sistemas operativos, lo único llamativo es que te enteras de que Windows no es mucho más diferente que otros sistemas.&lt;/p&gt;  &lt;p align="justify"&gt;Volviendo al tema (lo que me mola irme por las ramas), sobre la página ciento y pico (je je, me quedan todavía más de mil cien por leer, ¡qué emoción!) se pone a hablar del control de las excepciones del sistema operativo, y cómo son controladas en conjunción con el software de aplicación (ese que tu y yo hacemos) y el propio sistema. Y entonces te dice que si no tienes claro cómo funciona a nivel de programador, que mires los capítulos finales de &lt;i&gt;Windows via C/C++&lt;/i&gt;. Y como resulta que tengo ese libro en la lista de pendientes (hace unos años leí y estudié la misma versión pero mucho más antigua, y encima en castellano), pues dejé uno y me puse con el otro, máxime recordando que fueron precisamente esos capítulos los que no leí en la edición anterior.&lt;/p&gt;  &lt;p align="justify"&gt;El sistema de excepciones de Windows es muy potente y versátil, y todos deberíamos saber lo básico sobre él. Pero no, no voy a entrar en detalles sobre el mismo, simplemente os diré que funciona muy parecido a las excepciones de un lenguaje de programación, con la salvedad de que es el sistema operativo el que las lanza y las gestiona si no lo has hecho tu.&lt;/p&gt;  &lt;p align="justify"&gt;En Windows Vista y siguientes existe una aplicación que se llama &lt;i&gt;WerFault.exe&lt;/i&gt; y que seguro que habéis visto en ejecución. De hecho, cada vez que os peta un programa, es esa aplicación la que toma el control y saca la barra de progreso moviéndose y te permite unas u otras acciones una vez que ha hecho sus deberes.&lt;/p&gt;  &lt;p align="justify"&gt;Es decir, cuando una aplicación genera una excepción, o el sistema operativo dispara una causada por la aplicación (por ejemplo, una división entre cero o una escritura fuera de rango), se trastea con la pila de tu programa y se busca un controlador de excepción adecuado. Ojo, no estamos hablando de bloques try/catch, sino de bloques __try/__except… aunque a veces el control termina también en un catch, sobre todo si usamos C++ y hemos habilitado la compatibilidad de control de excepciones del sistema operativo (y esto no viene explicado así en el libro, que asume la compatibildad). En .NET no sé qué ocurrirá, pero no creo que haya mucha diferencia.&lt;/p&gt;  &lt;p align="justify"&gt;Si nuestro programa tiene un manejador para esa excepción, se ejecutará, y dependiendo de lo que devuelva, se reintentará la instrucción (de código máquina, así que ojo) que generó la excepción, se continuará como si nada hubiera pasado (y en este caso podríamos liarla todavía más gorda), o se seguirá buscando otro nuevo manejador. Es decir, independientemente de lo que quiera que hagamos en nuestro controlador, podemos decirle al sistema operativo que reintente, que ignore o que busque otro controlador más.&lt;/p&gt;  &lt;p align="justify"&gt;Una vez que se han recorrido todos los controladores adecuados, además de dos más extra que podemos instalar mediante &lt;i&gt;AddVectoredExceptionHandler()&lt;/i&gt; y &lt;i&gt;SetUnhandledExceptionFilter()&lt;/i&gt;, y siempre que se haya llegado al final de toda la cadena de excepciones (que es algo más larga y compleja de lo que aquí he expuesto) sin haber sido detenida, Windows lanzará el citado programa, y le pasará un manejador al proceso que está fallando, aparte de detener por completo la ejecución de todos sus hilos (en XP sólo se detenía el que fallaba) mediante unas APIs ALPC no documentadas.&lt;/p&gt;  &lt;p align="justify"&gt;Este programa, en base a algunas claves del registro, hará una cosa u otra. Como ha recibido los manejadores en modo heredado, tendrá control sobre el programa que está fallando. Aparte de añadir el evento correspondiente, podrá enviar el informe a Microsoft, o añadirlo a la lista de pendientes. Incluso existe la posibilidad de que ni siquiera aparezca, haciendo todas sus tareas de forma oculta, o incluso que no haga ninguna. Podemos incluso filtrar el comportamiento según qué aplicación haya fallado.&lt;/p&gt;  &lt;p align="justify"&gt;Después de que ha hecho sus tareas internas, si existe algún depurador registrado y si la configuración (o lo que hayamos elegido) lo permite, abrirá el programa &lt;i&gt;vsjitdebugger.exe&lt;/i&gt; que mostrará los depuradores registrados. De nuevo este programa recibe los manejadores de forma heredada, y mientras, nuestra aplicación está completamente muerta, esperando. Una vez que hemos elegido un depurador, éste será ejecutado pasando, otra vez, la información necesaria para que sea capaz de buscar y localizar la aplicación que ha fallado.&lt;/p&gt;  &lt;p align="justify"&gt;Es entonces cuando ésta se abrirá dentro del depurador, y si están disponibles los símbolos y demás, podremos ver qué ha fallado y por qué.&lt;/p&gt;  &lt;p align="justify"&gt;Si os fijáis, el tema no es sencillo ni de lejos. En primer lugar, el programa fallante no puede hacer nada porque podría estar en un estado indeterminado, con la memoria o la pila completamente corruptas, así que es el sistema operativo el que debe tomar el control y lanzar una nueva aplicación que se encargue de todo el paripé, que a su vez lanzará un depurador que no es tal, sino un &lt;i&gt;concentrador de depuradores&lt;/i&gt;, que al final sí, lanzará el depurador elegido, que tomará bajo su ala a nuestro programa petado.&lt;/p&gt;  &lt;p align="justify"&gt;¿Os dais cuenta lo complejo que es algo que asumimos de forma inconsciente como trivial? Pues no todo termina ahí, sino que es ahora el depurador el que debe meter las garras dentro de la aplicación defectuosa, insertándose en su espacio de direcciones de alguna manera.&lt;/p&gt;  &lt;p align="justify"&gt;Para finalizar, comentaros que esto no es más que un resumen de los capítulos 23, 24 y 25 de &lt;i&gt;&lt;a href="http://www.microsoft.com/learning/en/us/book.aspx?ID=11241&amp;amp;locale=en-us"&gt;Windows via C/C++&lt;/a&gt;&lt;/i&gt;, quinta edición.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=160776" width="1" height="1"&gt;</description><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/vista/default.aspx">vista</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/hardware/default.aspx">hardware</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/libros/default.aspx">libros</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><category domain="http://geeks.ms/blogs/rfog/archive/tags/Windows+7/default.aspx">Windows 7</category></item><item><title>Instalar QT en Visual Studio</title><link>http://geeks.ms/blogs/rfog/archive/2009/08/31/instalar-qt-en-visual-studio.aspx</link><pubDate>Mon, 31 Aug 2009 16:17:00 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:155037</guid><dc:creator>Rafael Ontivero</dc:creator><slash:comments>9</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/rfog/rsscomments.aspx?PostID=155037</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/rfog/commentapi.aspx?PostID=155037</wfw:comment><comments>http://geeks.ms/blogs/rfog/archive/2009/08/31/instalar-qt-en-visual-studio.aspx#comments</comments><description>&lt;p&gt;
&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES"&gt;Si has intentando instalar las &amp;uacute;ltimas
versiones de QT en Visual Studio habr&amp;aacute;s visto que la cosa no funciona como debe
ya que la biblioteca no compila, fallando en la parte de la construcci&amp;oacute;n de
WebKit, que viene a ser el componente para navegaci&amp;oacute;n Web de QT (Algo as&amp;iacute; como
el control OCX del IE, pero v&amp;aacute;lido para cualquier plataforma soportada).&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES"&gt;Pese a ello, puede resultar muy interesante
tener disponible esta plataforma en Visual C++, ya que, aunque la podemos instalar
con su IDE nativo, las funcionalidades de &amp;eacute;ste apenas le llegan a la suela de
los zapatos a las del de Microsoft, y no digamos ya las diferencias en cuanto a
rendimiento del compilador de Visual C++ frente al de GNU.&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES"&gt;Para quien no lo sepa, QT es un Framework
escrito en C++ que es capaz de generar ejecutables para Windows, MAC y Linux a
partir de un mismo c&amp;oacute;digo fuente. Es algo que todav&amp;iacute;a no he probado a hacer,
pero seguro que dentro de poco publico algo por aqu&amp;iacute;. En un principio QT era un
producto de TrollTech, y su licencia era propietaria. Con el tiempo la empresa
fue bajando los requisitos y, gracias sobre todo a KDE &amp;ndash;un escritorio Linux-,
al final sali&amp;oacute; con licencia doble. Es decir, pod&amp;iacute;as usarlo para hacer programas
propietarios pagando una licencia a TrollTech o hacer programas libres sin
tener que pagar nada.&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES"&gt;Luego TrollTech fue comprada por Nokia, y con
la versi&amp;oacute;n 4.4 de la biblioteca, &amp;eacute;sta pas&amp;oacute; a ser LGPL, lo que quiere decir que
se puede hacer cualquier tipo de desarrollo con ella, paguemos o no. En cierta
medida es algo l&amp;oacute;gico ya que Nokia no se dedica a vender QT, sino que usa QT
para sus m&amp;oacute;viles, y una forma de fomentar el desarrollo con esta biblioteca es
la de ofrecerla completamente gratuita. De todos modos hay un requisito que
pone Nokia, y es que s&amp;oacute;lo se puede usar la versi&amp;oacute;n de enlace din&amp;aacute;mico (con QT
metido en varias DLLs) en lugar de enlace est&amp;aacute;tico. Esto no est&amp;aacute; muy claro en
la licencia en s&amp;iacute;, pero pregunt&amp;eacute; y fue la respuesta que me dieron. Adem&amp;aacute;s,
tampoco es que sea muy viable un ejecutable de 20 megas, por poner un ejemplo.&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES"&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;strong&gt;&lt;span style="text-decoration:underline;"&gt;&lt;span lang="ES"&gt;Obtener
QT&lt;/span&gt;&lt;/span&gt;&lt;/strong&gt;&lt;span lang="ES"&gt;. El primer paso es bajarnos el SDK de QT, lo
que podemos hacer desde aqu&amp;iacute;: &lt;a href="http://qt.nokia.com/downloads"&gt;http://qt.nokia.com/downloads&lt;/a&gt;.
Debemos elegir la versi&amp;oacute;n LGPL/Free y dentro de ella bajarnos el &lt;i&gt;&lt;a href="http://qt.nokia.com/downloads/sdk-windows-cpp"&gt;Qt SDK for Open Source C++
development on Windows&lt;/a&gt;&lt;/i&gt;. Al hacer clic sobre el enlace citado se
iniciar&amp;aacute; autom&amp;aacute;ticamente la descarga de la &amp;uacute;ltima versi&amp;oacute;n del SDK.&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;strong&gt;&lt;span style="text-decoration:underline;"&gt;&lt;span lang="ES"&gt;Integraci&amp;oacute;n
con Visual Studio&lt;/span&gt;&lt;/span&gt;&lt;/strong&gt;&lt;span lang="ES"&gt;. Tambi&amp;eacute;n debemos bajarnos el &lt;a href="http://qt.nokia.com/downloads/visual-studio-add-in"&gt;Visual Studio Add-in&lt;/a&gt;,
que se integrar&amp;aacute; en Visual Studio versi&amp;oacute;n est&amp;aacute;ndar o superior (no creo que funcione
en la versi&amp;oacute;n Express).&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES"&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES"&gt;Una vez instalados ambos elementos, tendremos
en la carpeta C:\QT una nueva subcarpeta con la versi&amp;oacute;n instalada, que en mi
caso es la 2009.03. Esa instalaci&amp;oacute;n est&amp;aacute; completa, es decir, podremos usar el
QtCreator para construir nuestros proyectos, y de hecho no hay que hacer nada
m&amp;aacute;s si nos conformamos con las herramientas de que nos provee Nokia. &lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES"&gt;Cuando instalemos una nueva versi&amp;oacute;n, esta
quedar&amp;aacute; en una nueva carpeta tambi&amp;eacute;n colgando de C:\QT, y parece ser que la
idea de Nokia es sacar cuatro versiones al a&amp;ntilde;o. Aparte de la fecha, tambi&amp;eacute;n se
lleva un control de versiones. En el caso que nos ocupa, la versi&amp;oacute;n es la
4.5.2.&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES"&gt;De este modo podemos mantener diferentes
versiones del producto sin problemas, y de hecho incluso el Add-in de Visual
Studio entiende eso y podremos compilar para una o para otra seg&amp;uacute;n queramos.&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;strong&gt;&lt;span lang="ES"&gt;Una
cosa a tener en cuenta es que la ruta de instalaci&amp;oacute;n no puede tener espacios en
blanco&lt;/span&gt;&lt;/strong&gt;&lt;span lang="ES"&gt;, si no luego nos fallar&amp;aacute;n las herramientas, ya
sean de Visual Studio como del propio QtCreator.&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES"&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES"&gt;El siguiente paso es copiar la carpeta
C:\QT\2009.03 en C:\QT\2009.03-vc. Yo he adoptado esa filosof&amp;iacute;a: la carpeta con
la coletilla &amp;ldquo;-vc&amp;rdquo; es la versi&amp;oacute;n de Visual Studio. Evidementemente podemos
hacer esto directamente sobre la carpeta de instalaci&amp;oacute;n original, pero si
metemos la pata s&amp;oacute;lo nos quedar&amp;aacute; desinstalar, borrar la carpeta, y volver a
instalar (que tampoco es mala opci&amp;oacute;n).&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES"&gt;Si no fuera por los bugs que cito m&amp;aacute;s abajo,
ser&amp;iacute;a buena cosa borrar el contenido de las carpetas bin y lib de lo que hemos
copiado, aligerando as&amp;iacute; el espacio ocupado, pero debido a ello si lo hacemos no
seremos capaces de compilar QT para Visual Studio.&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES"&gt;Este paso que viene ahora es opcional pero
recomendable. Yo me he creado un fichero .bat en C:\QT que he llamado
&amp;ldquo;configure.bat&amp;rdquo; y que contiene lo siguiente:&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES"&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES"&gt;cd %1\qt&lt;br /&gt;configure &amp;ndash;shared
&amp;ndash;debug-and-release&lt;br /&gt;nmake&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES"&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES"&gt;El proceso normal para recompilar QT es ir a
la carpeta C:\QT\&amp;lt;versi&amp;oacute;n&amp;gt;\qt y ejecutar el programa configure (en
Windows, en Linux configure es un script) con las opciones de comandos
adecuadas. En general no es necesaria ninguna excepto la &amp;uacute;ltima si queremos que
nos construya las versiones debug y release en lugar de s&amp;oacute;lo la debug.&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES"&gt;Con el fichero .bat lo que hago es automatizar
este proceso, de modo que s&amp;oacute;lo tengo que irme a C:\QT y picar &amp;ldquo;configure
&amp;lt;carpeta&amp;gt;&amp;rdquo; para reconstruir la versi&amp;oacute;n que me interese.&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES"&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES"&gt;Nos hayamos creado o no el fichero .bat, ahora
tenemos que abrir una ventana de comandos de Visual Studio, situada
generalmente en Inicio -&amp;gt; All programs -&amp;gt; Visual Studio 2008 -&amp;gt; Visual
Studio Tools -&amp;gt; Visual Studio 2008 Command Prompt.&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES"&gt;Pero hay truco. Si queremos construir una
versi&amp;oacute;n de 64 bits, debemos elegir la consola de 64 bits, y si queremos un
sistema de 32, la normal. Deciros que yo todav&amp;iacute;a no he construido nunca una
versi&amp;oacute;n x64, pero por lo que dicen funciona igual de bien que la otra. S&amp;oacute;lo con
el tipo de ventana el script de QT sabr&amp;aacute; qu&amp;eacute; versi&amp;oacute;n compilar.&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES"&gt;Una vez que hemos abierto la ventana de
comandos, nos vamos a C:\QT si tenemos el fichero .bat o a
C:\QT\&amp;lt;versi&amp;oacute;n&amp;gt;\qt si no lo tenemos.&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES"&gt;En el primer caso picamos &amp;ldquo;configure
2009.03-vc&amp;rdquo;. En el segundo, &amp;ldquo;configure &amp;ndash;shared &amp;ndash;debug-and-release&amp;rdquo;. En ambos
casos nos preguntar&amp;aacute; qu&amp;eacute; versi&amp;oacute;n queremos. Tecleamos &amp;lsquo;o&amp;rsquo; de OpenSource, y luego
&amp;lsquo;y&amp;rsquo; para aceptar la licencia correspondiente. A partir de ah&amp;iacute; podemos irnos a
comer, cenar o echar la siesta.&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES"&gt;Si no hubiera bugs en el proceso de
compilaci&amp;oacute;n, en el primer caso el proceso se realizar&amp;iacute;a por completo, pero como
los hay nuestra compilaci&amp;oacute;n se interrumpir&amp;aacute; miserablemente. En el segundo caso,
una vez que configure haya terminado, debemos teclear &amp;ldquo;nmake&amp;rdquo;, cosa que podemos
hacer sin que el proceso de configurar haya acabado, y as&amp;iacute; casi mimetizamos
ambos procesos.&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES"&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES"&gt;Cuando se interrumpa la compilaci&amp;oacute;n, tendremos
un error del enlazador dici&amp;eacute;ndonos que faltan una serie de s&amp;iacute;mbolos. Tenemos
entonces que irnos a la carpeta
C:\QT\&amp;lt;versi&amp;oacute;n&amp;gt;\qt\src\3rdparty\webkit\WebCore\tmp\moc. Ah&amp;iacute; veremos dos
carpetas, release_shared y debug_shared. Entramos en la primera y borramos el
fichero &amp;ldquo;mocinclude.tmp&amp;rdquo;. Copiamos el fichero &amp;ldquo;moc_QnetworkReplyHandler.cpp&amp;rdquo; y
nos vamos a la otra carpeta, debug_shared, en donde volveremos a borrar
&amp;ldquo;mocinclude.tmp&amp;rdquo; y pegaremos el fichero. Si nos fijamos en esta carpeta hay ya
un fichero con ese nombre pero de tama&amp;ntilde;o cero.&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES"&gt;Es conveniente, aunque no obligatorio, &amp;ldquo;tocar&amp;rdquo;
el fichero &amp;ldquo;moc_QnetworkReplyHandler.cpp&amp;rdquo; de debug_shared para que sea
posterior a la fecha de creaci&amp;oacute;n (yo lo que hago es abrirlo con el bloc de
notas, a&amp;ntilde;ado y quito un espacio en blanco y lo guardo, as&amp;iacute; se cambian las
fechas.&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES"&gt;Ahora volvemos a nuestra consola y volvemos a
picar &amp;ldquo;nmake&amp;rdquo;. El proceso de compilaci&amp;oacute;n seguir&amp;aacute; hasta el final, por lo que de
nuevo podemos volver a echarnos otra siesta, irnos de parranda o leernos un par
de libros. Compilar QT es una tarea larga, incluso en un Quad con 8 GB de
memoria.&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES"&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES"&gt;Borrar &amp;ldquo;mocinclude.tmp&amp;rdquo; es necesario para
eliminar una cach&amp;eacute; que impide que el compilador vea los cambios que hemos
hecho, por lo que si s&amp;oacute;lo copiamos el fichero y seguimos con la ejecuci&amp;oacute;n del
proceso de compilaci&amp;oacute;n seguiremos teniendo el error.&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES"&gt;El motivo de por qu&amp;eacute; el otro fichero tiene
tama&amp;ntilde;o cero es harina de otro costal. QT utiliza un metacompilador llamado
&amp;ldquo;moc&amp;rdquo; para unir los &lt;i&gt;slots &lt;/i&gt;con las &lt;i&gt;signals&lt;/i&gt;, por lo que el fichero fuente
que hemos creado y que contiene elementos de acceso a la UI no vale
directamente, primero hay que pasarlo por el programa &amp;ldquo;moc&amp;rdquo;, que crear&amp;aacute; un
nuevo fichero ya v&amp;aacute;lido. &lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES"&gt;En el caso que nos ocupa, el fichero original
es &amp;ldquo;QnetworkReplyHandler.h&amp;rdquo;, pero por el motivo que sea (todo indica que es un
bug del programa &amp;ldquo;moc&amp;rdquo;), &amp;eacute;ste es incapaz de generar el equivalente .cpp
procesado para una build debug. Si se &lt;i&gt;mocquea&lt;/i&gt;
a mano con todas las opciones adecuadas, dice que no encuentra una clase v&amp;aacute;lida
y genera un fichero vac&amp;iacute;o. Hasta ah&amp;iacute; he llegado yo.&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES"&gt;Lo m&amp;aacute;s curioso de todo es que si borramos los
ficheros .a (que son de linux), los lib, los exe y las dll, el proceso de
compilaci&amp;oacute;n se produce de forma diferente y no se nos crean los ficheros
adecuados en la carpeta tmp\moc, de modo que no tenemos forma de copiar de la
parte release a la parte debug&amp;hellip; Ciertamente resulta algo extra&amp;ntilde;o y mosqueante,
y quiz&amp;aacute;s cuando tenga tiempo y ganas lo investigue m&amp;aacute;s a fondo.&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES"&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES"&gt;Ya hemos compilado QT. Ahora abrimos Visual
Studio y abrimos en la barra de men&amp;uacute;s QT -&amp;gt; QT Options, con lo que
obtendremos un cuadro de di&amp;aacute;logo en el que a&amp;ntilde;adiremos nuestra nueva versi&amp;oacute;n.
Aqu&amp;iacute; la primera vez debe aparecer vac&amp;iacute;o, as&amp;iacute; que hacemos clic en el bot&amp;oacute;n
&amp;ldquo;Add&amp;rdquo;. Se nos vuelve a abrir otro di&amp;aacute;logo y hacemos clic en los puntos
suspensivos que hay a la derecha del campo &amp;ldquo;Path&amp;rdquo;. Ahora navegamos hasta
C:\QT\2009.03-vc\qt y aceptamos. Ahora podemos darle un nombre a esta versi&amp;oacute;n
en el campo &amp;ldquo;Version Name&amp;rdquo;, por ejemplo &amp;ldquo;qt-2009.03&amp;rdquo;. Aceptamos todo y listo,
ya tenemos lista la integraci&amp;oacute;n.&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES"&gt;Si os hab&amp;eacute;is dado cuenta en el di&amp;aacute;logo de
opciones, es posible mantener varias versiones de QT y seleccionar la que nos
interese por defecto. En principio puede parecer una chorrada, pero cuando tienes
aplicaciones legadas con versiones antiguas que no compilan en versiones nuevas
de QT es una gran cosa.&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES"&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;&lt;span lang="ES"&gt;Con la integraci&amp;oacute;n con Visual Studio tenemos
hasta un asistente de proyecto. Si elegimos crear un proyecto nuevo desde la p&amp;aacute;gina
de inicio o desde el men&amp;uacute; normal, veremos que ahora disponemos de un nuevo tipo
de proyecto llamado &amp;ldquo;QT4 Projects&amp;rdquo; y que nos permite elegir entre diferentes opciones.
La normal ser&amp;aacute; &amp;ldquo;QT Application&amp;rdquo;, y dentro del asistente podremos elegir qu&amp;eacute;
modulos vamos a usar. Una vez creado un proyecto, si hacemos doble clic sobre
un fichero .ui, se nos abrir&amp;aacute; el QT Creator, que es un editor visual de
formularios y con el que podremos crear nuestras interfaces gr&amp;aacute;ficas igual que
se hace en C++Builder, C# o VB.&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=155037" width="1" height="1"&gt;</description><category domain="http://geeks.ms/blogs/rfog/archive/tags/c_2B002B00_/default.aspx">c++</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/linux/default.aspx">linux</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/lenguajes/default.aspx">lenguajes</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/Win32/default.aspx">Win32</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/MAC/default.aspx">MAC</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/QT/default.aspx">QT</category></item><item><title>Sobre C++ Builder 2010 y su historia</title><link>http://geeks.ms/blogs/rfog/archive/2009/08/10/sobre-c-builder-2010-y-su-historia.aspx</link><pubDate>Mon, 10 Aug 2009 12:25:00 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:153896</guid><dc:creator>Rafael Ontivero</dc:creator><slash:comments>13</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/rfog/rsscomments.aspx?PostID=153896</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/rfog/commentapi.aspx?PostID=153896</wfw:comment><comments>http://geeks.ms/blogs/rfog/archive/2009/08/10/sobre-c-builder-2010-y-su-historia.aspx#comments</comments><description>&lt;p align="justify"&gt;Tenemos una nueva versi&amp;oacute;n de &lt;a href="http://www.embarcadero.com/products/cbuilder"&gt;C++ Builder&lt;/a&gt; a la vuelta de la esquina, para el 24 de agosto si no me he equivocado en los c&amp;aacute;lculos. Ciertamente es una gran cosa que Embarcadero, los nuevos propietarios y quiero creer que definitivos, hayan devuelto este magn&amp;iacute;fico producto a la vida, como vamos a ver. [Si no te molan mis pajas mentales hist&amp;oacute;ricas y autobiogr&amp;aacute;ficas, salta hasta &lt;i&gt;C++ Builder 2010&lt;/i&gt;].&lt;/p&gt;
&lt;p align="justify"&gt;&lt;b&gt;&lt;span style="text-decoration:underline;"&gt;Un poco de historia&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p align="justify"&gt;Yo fui un furioso &lt;i&gt;borlander&lt;/i&gt;, hasta quiz&amp;aacute;s el nivel del fanatismo. El que haya le&amp;iacute;do mi &lt;i&gt;serie hist&amp;oacute;rica&lt;/i&gt; (&lt;a href="http://geeks.ms/blogs/rfog/archive/2009/04/17/la-historia-de-la-inform-225-tica-de-rfog.aspx"&gt;aqu&amp;iacute;&lt;/a&gt; y &lt;a href="http://geeks.ms/blogs/rfog/archive/2009/04/17/la-historia-de-la-inform-225-tica-de-rfog-y-ii.aspx"&gt;aqu&amp;iacute;&lt;/a&gt;) sabr&amp;aacute; que, en la academia en donde aprend&amp;iacute; C, nos pasaron el entorno de desarrollo Turbo C 2.0, que le daba como mil patadas al Microsoft C (y no es cosas de fundamentalismos, por aquella &amp;eacute;poca el Turbo C era la maravilla de las maravillas tecnol&amp;oacute;gicas en cuanto a compiladores de C). Por supuesto era pirata, como era pirata todo lo que usamos en aquella academia (por cierto, financiada con los primeros fondos de la UE para desempleados, de hecho nos pagaron una pasta gansa por ir a estudiar)...&lt;/p&gt;
&lt;p align="justify"&gt;&lt;b&gt;&lt;span style="text-decoration:underline;"&gt;La academia.&lt;/span&gt;&lt;/b&gt; De la academia aquella recuerdo una an&amp;eacute;cdota (por llamarla de alguna manera) que quiz&amp;aacute;s no deber&amp;iacute;a contar pero que voy a hacer. No recuerdo la fecha exacta en que estudiamos, pero era cerca del verano, y all&amp;iacute; dentro hac&amp;iacute;a un calor m&amp;aacute;s que sofocante, lo que, junto a calor generado por los ordenadores hac&amp;iacute;a que apenas pudi&amp;eacute;ramos concentrarnos en lo que est&amp;aacute;bamos haciendo. Tambi&amp;eacute;n ten&amp;iacute;amos otro problema, y es que los ordenadores eran, por decirlo suavemente, una mierda. A la par que antiguos, ninguno funcionaba bien, como tampoco los profesores eran muy buenos que digamos. &lt;/p&gt;
&lt;p align="justify"&gt;Vamos, que &amp;eacute;ramos el culo del mundo, una tapadera para que el due&amp;ntilde;o de la academia se forrara con los fondos aquellos. Nuestras quejas ca&amp;iacute;an en saco roto, ya fu&amp;eacute;ramos a hablar con el due&amp;ntilde;o de la empresa como al INEM de nuestra ciudad. Promet&amp;iacute;an pero no cumpl&amp;iacute;an, y algunos de nosotros est&amp;aacute;bamos all&amp;iacute; para aprender, no para cobrar. As&amp;iacute; que ni cortos ni perezosos, tres de nosotros cogimos el autob&amp;uacute;s y nos fuimos a la oficina del INEM en Alicante y expusimos el tema: que ten&amp;iacute;amos ordenadores que no funcionaban, que nos mor&amp;iacute;amos de calor, que los profesores sab&amp;iacute;an menos que nosotros (que no era poco), que nos hab&amp;iacute;amos quejado al due&amp;ntilde;o de la academia y al INEM de Elda y que no nos hab&amp;iacute;an hecho caso, que cuando ven&amp;iacute;a el propietario se iba a comer con el encargado de los cursos del paro y aqu&amp;iacute; haya paz y all&amp;iacute; gloria, y que si no nos hac&amp;iacute;an caso no tendr&amp;iacute;amos inconveniente en irnos a quejar a Valencia o a Madrid...&lt;/p&gt;
&lt;p align="justify"&gt;Buenooooooooo, la que se arm&amp;oacute;. Nosotros, callados como putas, al d&amp;iacute;a siguiente volvimos a clase como si nada hubiera pasado, y ese mismo d&amp;iacute;a cay&amp;oacute; el Armaged&amp;oacute;n. Vinieron dos se&amp;ntilde;ores muy trajeados, echaron un vistazo, llamaron por tel&amp;eacute;fono al due&amp;ntilde;o, el profe estaba blanco como la cera, nos mandaron a todos a casa hasta nuevo aviso y... en cosa de tres d&amp;iacute;as ten&amp;iacute;amos profesores competentes, aire acondicionado y lo &amp;uacute;ltimo de lo &amp;uacute;ltimo en ordenadores. A partir de ese momento, aprendimos.&lt;/p&gt;
&lt;p align="justify"&gt;***&lt;/p&gt;
&lt;p align="justify"&gt;Ya lo he comentado con anterioridad, para mi aprender C fue lo m&amp;aacute;s, la revelaci&amp;oacute;n del maravilloso mundo del desarrollo. Y m&amp;aacute;s todav&amp;iacute;a con el Turbo C, primer concepto de lo que ahora nos es tan consustancial y sin el cual muchos de nosotros no sabr&amp;iacute;amos vivir. Luego vinieron otras cosas, como Visual Basic y Delphi, elementos que no pod&amp;iacute;an coexistir sin un IDE. Y con ellos tambi&amp;eacute;n naci&amp;oacute; lo que yo llamo la generaci&amp;oacute;n de los pseudoprogramadores. Y que nadie se me mosquee. Para un buen programador que pueda haber en VB o Delphi, hay 10 p&amp;eacute;simos. En C (y C++) tambi&amp;eacute;n los hay, pero esos se paran y cambian a otro lenguaje cuando est&amp;aacute;n haciendo un programa de 10.000 l&amp;iacute;neas y ya no saben c&amp;oacute;mo meterle mano (ni ellos ni nadie m&amp;aacute;s). As&amp;iacute; que en esos otros lenguajes est&amp;aacute;n, tambi&amp;eacute;n, los de C que no saben.&lt;/p&gt;
&lt;p align="justify"&gt;Del Turbo C pas&amp;eacute; al Turbo C++, no recuerdo qu&amp;eacute; versi&amp;oacute;n, creo que tambi&amp;eacute;n la 2.0, aunque mi memoria se vuelve como agua con el tema de las versiones aquellas. S&amp;eacute; que de las versiones &amp;quot;Turbo&amp;quot; se pas&amp;oacute; las &amp;quot;Borland&amp;quot;, que cambiaban -y mejoraban- el concepto del IDE. Aquella (cuando la tienda y algo despu&amp;eacute;s) fue mi &amp;eacute;poca, m&amp;aacute;s que de programar en C, de hacerlo en Clipper. Y las cosas est&amp;aacute;n confusas en mis meninges. S&amp;eacute; que manej&amp;eacute; varias versiones de ambos productos, todas ellas ejecutando en MS-DOS, aunque con algunas ya se pod&amp;iacute;a desarrollar para Windows.&lt;/p&gt;
&lt;p align="justify"&gt;Bueno, el tema es que en su momento compr&amp;eacute; el Borland C++ 3.0, que fue mi primera herramienta seria (y tomada en serio) de desarrollo. Si no recuerdo mal, aquello ten&amp;iacute;a un IDE para DOS y otro para Windows. Ya os pod&amp;eacute;is imaginar c&amp;oacute;mo funcionar&amp;iacute;a la versi&amp;oacute;n Windows, arrastr&amp;aacute;ndose como una tortuga reum&amp;aacute;tica. Lo que no recuerdo eran pantallas azules ni ca&amp;iacute;das extra&amp;ntilde;as, que no era poco. Adem&amp;aacute;s, yo usaba la versi&amp;oacute;n de MS-DOS, mucho m&amp;aacute;s estable y funcional.&lt;/p&gt;
&lt;p align="justify"&gt;Al poco de comprar (s&amp;iacute;, he dicho comprar) la versi&amp;oacute;n 3.0, sali&amp;oacute; la 3.1, que soportaba Windows 3.1 y que apenas ten&amp;iacute;a otras mejoras que usar el SDK (o como quiera que se llamara en aquella &amp;eacute;poca) de la susodicha versi&amp;oacute;n de Windows. Aquello me toc&amp;oacute; un poco los cojones porque hac&amp;iacute;a nada que hab&amp;iacute;a pasado por caja, as&amp;iacute; que la consegu&amp;iacute; pirata. En aquellos tiempos no hac&amp;iacute;a nada &amp;uacute;til con aquellas herramientas m&amp;aacute;s que usar los manuales para aprender C++ y programaci&amp;oacute;n bajo Windows.&lt;/p&gt;
&lt;p align="justify"&gt;De esos a&amp;ntilde;os recuerdo haber comprado el libro &lt;i&gt;Aplique C++&lt;/i&gt; de Bruce Eckel, que acabo de recuperar de mi biblioteca. Si bien dije en una entrada anterior que cubr&amp;iacute;a el CFRONT 2.1, ahora veo que no es cierto, que s&amp;oacute;lo llega al 2.0, y encima en un cap&amp;iacute;tulo aparte. A&amp;ntilde;adamos los diez o doce manuales que tra&amp;iacute;a el Borland C++ 3.0 y ah&amp;iacute; ten&amp;eacute;is mi aprendizaje de C++, que ten&amp;iacute;a que tomarme con bastante calma, ya que aprender un lenguaje estudiando su sintaxis en formato &lt;i&gt;backus-nair&lt;/i&gt; tiene su m&amp;eacute;rito (por eso me compr&amp;eacute; el libro citado).&lt;/p&gt;
&lt;p align="justify"&gt;Despu&amp;eacute;s vino Borland C++ 4.0, que ya hac&amp;iacute;a enfoque en Windows y dejaba las herramientas de MS-DOS como secundarias, y ah&amp;iacute; fue cuando yo empec&amp;eacute; a usar el IDE de Windows como mi editor de desarrollo, usara Clipper o el propio Borland. En aquellos a&amp;ntilde;os una unidad de CD val&amp;iacute;a una pasta gansa, aunque en alg&amp;uacute;n momento Creative (o como se llamara entonces), sac&amp;oacute; la Sound Blaster 16 con unidad de CD, que yo compr&amp;eacute;, m&amp;aacute;s que nada por el lector, porque la m&amp;uacute;sica no me hac&amp;iacute;a ni fu ni fa, y encima hacer funcionar aquello era toda una odisea y se com&amp;iacute;a buena parte del procesador cuando estaba sonando.&lt;/p&gt;
&lt;p align="justify"&gt;Pues bien, yo ten&amp;iacute;a unidad de CD, pero me equivoqu&amp;eacute; al pedir la versi&amp;oacute;n 4.0 y la recib&amp;iacute; en disquetes, o m&amp;aacute;s bien ignoraba que hubiera versi&amp;oacute;n en CD. Re&amp;iacute;ros un rato, creo que eran 40 disquetes de 3.5&amp;quot; y alguno m&amp;aacute;s de 5 y 1/4. Y, por supuesto, otros diez o doce manuales en papel. Lo que m&amp;aacute;s me toc&amp;oacute; las narices fue que el disquete 1 se me rompi&amp;oacute; al poco de tener aquello, y me toc&amp;oacute; conseguirlo pirata porque el distribuidor en Espa&amp;ntilde;a se negaba a creerse eso de que &lt;i&gt;se me hab&amp;iacute;a roto&lt;/i&gt;.&lt;/p&gt;
&lt;p align="justify"&gt;Incidentalmente, esa fue la primera vez que me plantee seriamente el motivo de comprar software original, si las pegas eran superiores a las ventajas. Lo &amp;uacute;nico que me decidi&amp;oacute; a seguir siendo legal en ese aspecto era que los juegos conseguidos pirata terminaban haciendo cosas raras -como colgarse o no funcionar bien-, y se supon&amp;iacute;a que el software comprado, al venir de una fuente fiable, no traer&amp;iacute;a errores en el soporte. M&amp;aacute;s tarde descubr&amp;iacute; que a los legales tambi&amp;eacute;n les pasaba. En fin.&lt;/p&gt;
&lt;p align="justify"&gt;Luego vino la versi&amp;oacute;n 4.5, que tampoco compr&amp;eacute; porque la vi como una simple mejora. M&amp;aacute;s tarde sacaron &lt;i&gt;Borland C++ 4.5 and Database Tools&lt;/i&gt;, que consegu&amp;iacute;, de nuevo, pirata, porque aquello de hacer bases de datos con C++ me llam&amp;oacute; mucho la atenci&amp;oacute;n. Era como mezclar churras con merinas, o al menos as&amp;iacute; lo pensaba yo, que viv&amp;iacute;a muy conforme con mi Clipper y mi MS-DOS, aunque estaba profundizando, a nivel diletante, en Win16. Pero lo de &lt;i&gt;database tools&lt;/i&gt; era como una falacia, manejar bases de datos con C++ era algo como los Trabajos de H&amp;eacute;rcules, con lo que ahora s&amp;eacute; eran los reci&amp;eacute;n nacidos interfaces COM (aunque se llamaran OLE y OLE2). Inmediatamente despu&amp;eacute;s sali&amp;oacute; la versi&amp;oacute;n 4.52 como &lt;i&gt;bug fix&lt;/i&gt; de la anterior.&lt;/p&gt;
&lt;p align="justify"&gt;Cuando sali&amp;oacute; &lt;i&gt;Borland C++ 5.0&lt;/i&gt; pas&amp;eacute; por caja, y volv&amp;iacute; a recibir una nueva espuerta de manuales, aunque ya ped&amp;iacute; expresamente la versi&amp;oacute;n en CD. O ven&amp;iacute;a en CD y si quer&amp;iacute;as disquetes ten&amp;iacute;as que pagarlos (y pedirlos) aparte, no recuerdo exactamente. Esta versi&amp;oacute;n me la tom&amp;eacute; muy en serio y me puse a estudiarla a fondo, sobre todo el IDE y lo que pod&amp;iacute;a hacer, con aquellas plantillas de metaproyectos, y el acceso a sus interioridades del mismo mediante un lenguaje de script orientado a objetos. Aparte el compilador era bastante bueno y generaba el mejor c&amp;oacute;digo posible. Poco despu&amp;eacute;s recib&amp;iacute;, gratis, la versi&amp;oacute;n 5.02, otro &lt;i&gt;bug fix&lt;/i&gt;.&lt;/p&gt;
&lt;p align="justify"&gt;M&amp;aacute;s o menos entonces tambi&amp;eacute;n descubr&amp;iacute; algo que me llen&amp;oacute; de gozo: los parches. S&amp;iacute;, los fabricantes sacaban peque&amp;ntilde;os programas m&amp;aacute;s o menos gratuitos que solucionaban algunos problemas de sus productos. Ciertamente el uso que yo hac&amp;iacute;a del Borand C++ no tra&amp;iacute;a a la palestra ning&amp;uacute;n fallo si no era que ten&amp;iacute;as que tener cuidado con el orden de declaraci&amp;oacute;n de las variables y que a veces no se llamaban a los destructores. Casi nada, pero en mi caso no ten&amp;iacute;a importancia, lo ve&amp;iacute;a como algo normal. Claro, era lo &amp;uacute;nico que hab&amp;iacute;a -y ten&amp;iacute;a. No obstante, para la versi&amp;oacute;n 5.02 consegu&amp;iacute;, con mucho sudor, dos parches que apliqu&amp;eacute; con m&amp;aacute;s satisfacci&amp;oacute;n que utilidad, porque no vi diferencia entre antes y despu&amp;eacute;s.&lt;/p&gt;
&lt;p align="justify"&gt;***&lt;/p&gt;
&lt;p align="justify"&gt;&lt;b&gt;Visual C++.&lt;/b&gt; No os pens&amp;eacute;is que s&amp;oacute;lo viv&amp;iacute;a de Borland. No recuerdo la sincron&amp;iacute;a entre versiones, pero en su momento consegu&amp;iacute; Visual C++ 4 y luego la versi&amp;oacute;n 5, y ciertamente no ten&amp;iacute;an nada que hacer frente a Borland. Con Visual C++ 6.0 la cosa cambi&amp;oacute; un poco, porque al parecer el mercado se hab&amp;iacute;a volcado hacia MFC en lugar de OWL (que tambi&amp;eacute;n estudi&amp;eacute;, como estudi&amp;eacute; el poco valorado Turbo Vision, una biblioteca de clases potent&amp;iacute;sima para hacer lo mismo que con OWL pero para DOS). Sin embargo, en comparaci&amp;oacute;n, MFC era (y sigue siendo, al menos hasta la versi&amp;oacute;n de Visual C++ 2008) una mierda, comparada con OWL. Esta &amp;uacute;ltima encapsulaba y abstra&amp;iacute;a mediante orientaci&amp;oacute;n a objetos real el api de Win32, mientras que MFC no es m&amp;aacute;s que un envoltorio pseudo orientado a objetos de Win32. No obstante, se ve una tendencia a cambiar con Visual C++ 2008 Service Pack 1, en la que MFC, tras haber permanecido pr&amp;aacute;cticamente est&amp;aacute;tica desde la versi&amp;oacute;n 6.0, parece estar evolucionando hacia algo m&amp;aacute;s decente. Y es que la competencia de QT le anda a la zaga... con muchas ventajas frente a MFC.&lt;/p&gt;
&lt;p align="justify"&gt;Las versiones de Visual C++ las he conseguido por canales un tanto tortuosos. La 4 creo que me la regalaron por algo, simplemente me dieron el CD en una caja precintada. No puedo recordar por qu&amp;eacute; ni qui&amp;eacute;n, pero s&amp;eacute; que fue gratis. La 5 la compr&amp;eacute; con una licencia de estudiante, y la 6 tambi&amp;eacute;n fue regalada. Por m&amp;aacute;s que pienso, no consigo recordar c&amp;oacute;mo las consegu&amp;iacute;, de hecho la 6 fue Visual Studio 6.0, que tambi&amp;eacute;n tra&amp;iacute;a Visual Basic y Visual InterDev o algo as&amp;iacute;, que jam&amp;aacute;s he sabido para qu&amp;eacute; serv&amp;iacute;a. Y tambi&amp;eacute;n s&amp;oacute;lo la caja, sin manuales. &lt;/p&gt;
&lt;p align="justify"&gt;Luego vino Visual Studio 2003 como elemento al comprar una suscripci&amp;oacute;n a la MSDN, y luego me hicieron MVP y pude acceder a todas las versiones sin problemas, pero esa es otra historia.&lt;/p&gt;
&lt;p align="justify"&gt;***&lt;/p&gt;
&lt;p align="justify"&gt;&lt;b&gt;C++ Builder.&lt;/b&gt; Bueno, el tema es que, una vez que me decid&amp;iacute; a aprender en serio lo que tra&amp;iacute;a Borland C++ 5.02, el fabricante sac&amp;oacute; algo nuevo llamado C++ Builder. Como ya era cliente fijo de Database DM, me enviaron la publicidad del producto, que le&amp;iacute; pero no entend&amp;iacute;. As&amp;iacute; que llam&amp;eacute; a la empresa, y una amable chica me estuvo contando que eso era &amp;quot;lo nuevo de Borland, era programar como en Visual Basic o Delphi pero en C++. Hab&amp;iacute;a unos componentes que tu soltabas sobre la ventana y ya ten&amp;iacute;as hecha la parte visual de la aplicaci&amp;oacute;n&amp;quot;. Si no me dijo exactamente eso, lo que me cont&amp;oacute; no se alejaba mucho de lo citado. &lt;/p&gt;
&lt;p align="justify"&gt;Y menos mal que lo compr&amp;eacute;. Aquello supuso una revoluci&amp;oacute;n personal, abandon&amp;eacute; definitivamente Clipper (de hecho le di a todos mis clientes el c&amp;oacute;digo fuente de sus respectivas aplicaciones junto a propio Clipper) y me puse a estudiar aquello. No es que viviera de programar, que no lo hac&amp;iacute;a, pero alg&amp;uacute;n que otro cliente s&amp;iacute; ten&amp;iacute;a, y tampoco era dejarlos en la estacada, de hecho siempre les he mantenido los programas hasta que los han abandonado, aunque s&amp;eacute; de uno que todav&amp;iacute;a tiene y usa la &lt;i&gt;agenda doble&lt;/i&gt; que le hice. Bueno, ya no, porque hace cosa de un par de a&amp;ntilde;os el hombre muri&amp;oacute;, pero si siguiera vivo seguro que la estar&amp;iacute;a usando.&lt;/p&gt;
&lt;p align="justify"&gt;Con C++ Builder y una oportunidad que tuve pude dedicarme definitivamente al desarrollo y no a ir a salto de mata haciendo programas aqu&amp;iacute; y all&amp;iacute; (mi trabajo diario y normal no era m&amp;aacute;s que un modo de supervivencia). Una cosa que no he dicho es que de vez en cuando hac&amp;iacute;a algo embebido sin sistema operativo, incluso desde un PC &amp;quot;a pelo&amp;quot; (evidentemente en modo real x86 y sin muchas zarandajas). Sin embargo, esta oportunidad me puso en el camino que yo quer&amp;iacute;a, y gracias a mi doble vertiente de programador de PC y no-PC he sobrevivido m&amp;aacute;s que bien, y espero hacerlo en un futuro.&lt;/p&gt;
&lt;p align="justify"&gt;La siguiente versi&amp;oacute;n fue C++ Builder 3 (no hubo 2 por un tema de sincronizaci&amp;oacute;n con Delphi), que tambi&amp;eacute;n compr&amp;eacute;. Y luego la 4. Y entonces se me hincharon las pelotas y decid&amp;iacute; dejar de hacer el tonto comprando siempre lo mismo y me plant&amp;eacute; con C++ Builder 4, sus parches y sus bugs, que no eran pocos.&lt;/p&gt;
&lt;p align="justify"&gt;M&amp;aacute;s o menos entonces Borland entr&amp;oacute; en su fase &amp;quot;Inprise, me cambio el nombre porque no tengo ni *** idea de qu&amp;eacute; estoy haciendo&amp;quot; (Parece ser que las empresas tambi&amp;eacute;n sufren crisis existenciales, y tambi&amp;eacute;n parece ser que para ellas no vale eso de subirse a una monta&amp;ntilde;a y preguntarse por el sentido de la vida). Y dej&amp;oacute; de cuidar sus herramientas de desarrollo. Y empez&amp;oacute; a dar bandazos. Sacaron el Kylix, un producto adelantado a su tiempo que ellos mismos mataron. Y otra herramienta de desarrollo en C++ multiplataforma que ahora no recuerdo c&amp;oacute;mo se llama, que tambi&amp;eacute;n mataron. Compraron CodeWright y mataron sus productos. En fin, que de tontos est&amp;aacute; lleno el mundo.&lt;/p&gt;
&lt;p align="justify"&gt;En el tema del C++ sacaron las versiones 5 y 6 del C++ Builder, que no eran otra cosa que la 4 con la cara lavada. Y con cada versi&amp;oacute;n, m&amp;aacute;s bugs sin solucionar, hasta que mataron el producto. Supongo que con Delphi fue m&amp;aacute;s o menos lo mismo. Yo us&amp;eacute; la 5 y la 6 pero pirateadas, aunque mi herramienta principal siempre fue, durante muchos a&amp;ntilde;os, la 4.&lt;/p&gt;
&lt;p align="justify"&gt;Parece ser que algo estaba ocurriendo entre bambalinas, porque a partir de la 6 el entorno fue completamente remodelado intentando imitar las versiones de Visual Studio, con nuevas caracter&amp;iacute;sticas y nuevas potencialidades. Cuando fueron saliendo las sucesivas versiones X, 2006, 2007 y 2009 yo estaba desarrollando con C# (no muy convencido, la verdad) y Visual C++ en mi trabajo actual (de hecho aprovech&amp;eacute; el cambio entre el anterior y el actual para cambiar por completo de herramientas). Yo pensaba que ambos funcionar&amp;iacute;an mejor que el C++ Builder, pero no es cierto. En el caso de .NET y C#, como te salgas de lo que Microsoft ha determinado como est&amp;aacute;ndar, la mayor&amp;iacute;a de cosas no funcionan, aunque poco a poco lo van solucionando. Por otro lado, el compilador de C++ de Microsoft es muy bueno, bastante mejor que el de Borland, pero Visual Studio es otra cosa. En relaci&amp;oacute;n a C++ no anda muy fino, m&amp;aacute;s que nada porque la implementaci&amp;oacute;n b&amp;aacute;sica es para C#, y C++ anda metido con calzador. Esperemos que Visual C++ 2010 solucione el tema (y personalmente creo que, si no lo soluciona, al menos lo mejora sensiblemente).&lt;/p&gt;
&lt;p align="justify"&gt;Otra cosa es MFC, que son dif&amp;iacute;ciles de aprender y retorcidas a m&amp;aacute;s no poder. T&amp;eacute;cnicamente hablando no entiendo por qu&amp;eacute; gan&amp;oacute; a OWL, pero la vida es as&amp;iacute;. Y ahora que m&amp;aacute;s o menos me defiendo con MFC, a&amp;ntilde;oro con bastante intensidad el C++ Builder y he abandonado desarrollar con C# y .NET mientras pueda evitarlo.&lt;/p&gt;
&lt;p align="justify"&gt;***&lt;/p&gt;
&lt;p align="justify"&gt;Pero con C++ Builder 2009 estoy viendo un agradable cambio. Cuando sali&amp;oacute; la versi&amp;oacute;n 2007 o 2006, no recuerdo bien, fui invitado a una presentaci&amp;oacute;n y, como coincid&amp;iacute;a con el SIMO e iba a ir con mi jefe, pues asist&amp;iacute;. All&amp;iacute; fue donde vi por primera vez a Octavio Hern&amp;aacute;ndez, y all&amp;iacute; fue donde dej&amp;eacute; caer mi pregunta bomba: &amp;quot;&amp;iquest;Va Borland a seguir publicando versi&amp;oacute;n tras versi&amp;oacute;n de este &lt;i&gt;nuevo&lt;/i&gt; C++ Builder sin corregir los cientos y cientos de bugs que hay pendientes?&amp;quot;, de hecho creo que asist&amp;iacute; s&amp;oacute;lo por preguntar eso. Ciertamente cuando tradujeron aquello al ingl&amp;eacute;s todos quedaron bastante incomodados, pero las muestras de adhesi&amp;oacute;n a mi pregunta entre el p&amp;uacute;blico eran evidentes. As&amp;iacute; que creo que fue David Dean el que dijo que s&amp;iacute;, que &amp;eacute;l promet&amp;iacute;a que los errores se solucionar&amp;iacute;an.&lt;/p&gt;
&lt;p align="justify"&gt;Yo hice como que me lo cre&amp;iacute;a pero interiormente lo ten&amp;iacute;a claro: esa es la respuesta que tienen que dar, de hecho segu&amp;iacute; ignorando el producto. La 2006 fue una versi&amp;oacute;n puente, la 2007 estabiliz&amp;oacute; muchas cosas y la 2009 significa el paso de ANSI a Unicode en la VCL, ciertos avances en C++ como la inclusi&amp;oacute;n de la biblioteca &lt;i&gt;boost&lt;/i&gt; y algunos avances sobre C++0x.&lt;/p&gt;
&lt;p align="justify"&gt;Y resulta que s&amp;iacute;, que s&amp;iacute; se est&amp;aacute;n preocupando de los bugs. Por ejemplo, la versi&amp;oacute;n 2007 tiene doce parches, y la 2009 cuatro que son seis, porque los sacan de dos en dos (uno para el compilador y el IDE y otro para el soporte de bases de datos). Y eso me hace querer volver, aunque reconozco que me he perdido muchos pasos en relaci&amp;oacute;n a la evoluci&amp;oacute;n de la VCL (desde la versi&amp;oacute;n 4), y es dif&amp;iacute;cil de recuperar.&lt;/p&gt;
&lt;p align="justify"&gt;&lt;b&gt;&lt;span style="text-decoration:underline;"&gt;C++ Builder 2010&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p align="justify"&gt;Cuando escribo esto faltan 14 d&amp;iacute;as para la salida del producto. Podemos ver &lt;a href="http://etnaweb04.embarcadero.com/rad-studio-2010/"&gt;aqu&amp;iacute;&lt;/a&gt; un reloj de cuenta atr&amp;aacute;s y un v&amp;iacute;deo con las novedades, en ingl&amp;eacute;s.&lt;/p&gt;
&lt;p align="justify"&gt;B&amp;aacute;sicamente mejoran el IDE con nuevos elementos:&lt;/p&gt;
&lt;p align="justify"&gt;&amp;middot; IDE Insight: Es una ventana de b&amp;uacute;squeda que muestra las interioridades del IDE. Es decir, si uno quiere compilar pero no encuentra la opci&amp;oacute;n por ning&amp;uacute;n lado, abre esta ventana, busca &amp;quot;compile&amp;quot; y le aparecen todas las cosas que tiene el IDE con esa funcionalidad y seg&amp;uacute;n el contexto actual. A simple vista parece una tonter&amp;iacute;a, pero es una herramienta fant&amp;aacute;sticamente poderosa.&lt;/p&gt;
&lt;p align="justify"&gt;&amp;middot; Formateador de c&amp;oacute;digo, algo que ya trae Visual Studio desde al menos la versi&amp;oacute;n 2003: seleccionas un bloque de c&amp;oacute;digo y formatea correctamente los indentados.&lt;/p&gt;
&lt;p align="justify"&gt;&amp;middot; Explorador de clases. Parece ser que es bastante potente y no s&amp;oacute;lo est&amp;aacute; limitado a nuestro proyecto, sino que puedes echar un vistazo por cualquier biblioteca instalada. A efectos comparativos, es una mezcla de la ventana de &amp;quot;Class View&amp;quot; y de &amp;quot;Object Browser&amp;quot; del Visual Studio con proyectos .NET.&lt;/p&gt;
&lt;p align="justify"&gt;&amp;middot; M&amp;aacute;s visualizadores de datos en el depurador. Ciertamente en esto siempre ha flojeado un poco el IDE. Esperemos que ahora est&amp;eacute; solucionado.&lt;/p&gt;
&lt;p align="justify"&gt;&amp;middot; Control de Hilos en Depuraci&amp;oacute;n: una ventana de depuraci&amp;oacute;n especial que permite trastear con los hilos de nuestra aplicaci&amp;oacute;n, como ejecutar s&amp;oacute;lo uno de ellos, ejecutar con seg&amp;uacute;n qu&amp;eacute; hilos dormidos, etc. Seg&amp;uacute;n dice el v&amp;iacute;deo es capaz de detectar deadlocks y similares.&lt;/p&gt;
&lt;p align="justify"&gt;&amp;middot; Compilaci&amp;oacute;n en &lt;i&gt;background&lt;/i&gt;. A estas alturas suena algo risible que se presente eso como una novedad, cuando era algo que ya ten&amp;iacute;a el Turbo C, tuvo el Borland C y el Borland C++, y ha tenido de siempre Visual C++...&lt;/p&gt;
&lt;p align="justify"&gt;&amp;middot; Traer&amp;aacute; integrado el SDK de Windows 7, por lo que se adelanta en cierta medida a Microsoft.&lt;/p&gt;
&lt;p align="justify"&gt;Por desgracia parece ser que el compilador de C++ de Borland (perd&amp;oacute;n, Embarcadero) sigue siendo el mismo pobrecito de siempre, sobrepasado por los est&amp;aacute;ndares y bastante falt&amp;oacute;n al respeto.&lt;/p&gt;
&lt;p align="justify"&gt;Embarcadero est&amp;aacute; continuamente poniendo informaci&amp;oacute;n sobre las novedades de la nueva versi&amp;oacute;n en el canal de Twitter llamado &lt;a href="http://twitter.com/EmbarcaderoTech"&gt;EmbarcaderoTech&lt;/a&gt;, y hay v&amp;iacute;deos en &lt;i&gt;casi&lt;/i&gt; castellano y en portugu&amp;eacute;s (que se medio entiende) &lt;a href="http://blogs.embarcadero.com/andreanolanusse/2009/08/04/ideinsight-una-de-las-novedades-de-delphi-2010-y-cbuilder-2010/"&gt;aqu&amp;iacute;&lt;/a&gt;. &lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=153896" width="1" height="1"&gt;</description><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/rationale/default.aspx">rationale</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><category domain="http://geeks.ms/blogs/rfog/archive/tags/Windows+7/default.aspx">Windows 7</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/C_2B002B00_+Builder/default.aspx">C++ Builder</category></item><item><title>Todo lo que quisiste saber sobre las DLL y no te atreviste a preguntar (I)</title><link>http://geeks.ms/blogs/rfog/archive/2009/06/29/todo-lo-que-quisiste-saber-sobre-las-dll-y-no-te-atreviste-a-preguntar-i.aspx</link><pubDate>Mon, 29 Jun 2009 11:56:27 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:151465</guid><dc:creator>Rafael Ontivero</dc:creator><slash:comments>6</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/rfog/rsscomments.aspx?PostID=151465</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/rfog/commentapi.aspx?PostID=151465</wfw:comment><comments>http://geeks.ms/blogs/rfog/archive/2009/06/29/todo-lo-que-quisiste-saber-sobre-las-dll-y-no-te-atreviste-a-preguntar-i.aspx#comments</comments><description>&lt;p align="justify"&gt;Las DLL tuvieron su origen cuando se quiso compartir código común entre diferentes aplicaciones para así ahorrar algo de espacio en disco (posiblemente &lt;i&gt;espacio en disquetes&lt;/i&gt;). Esto requirió que Windows implementara ciertos modelos de memoria bastante complicados para la época (de la historia de Unix/Linux poco sé, si la idea de compartir bibliotecas en tiempo de ejecución fue anterior o posterior –supongo que anterior, aunque vaya usté a saber-), pero era hacerlo así o limitar gravemente a Windows.&lt;/p&gt;  &lt;p align="justify"&gt;Ese modelo de memoria permitió otras cosas, como que las DLL solo pudieran tener un juego de datos para todos los programas que las usaran (con la posibilidad también de contener datos únicos para cada aplicación), ahorrando todavía más memoria. Una desventaja es que un programa maleducado podía tirar al suelo no sólo a otros que usaran una misma DLL, sino al propio Windows, y eso teniendo en cuenta que la DLL estuviera bien construida y no fuera la propia DLL la que tumbara al sistema.&lt;/p&gt;  &lt;p align="justify"&gt;Ahora las cosas son bastante diferentes, cada DLL se ejecuta en el mismo espacio de direcciones que la aplicación que la llama, de manera que ya no comparten memoria ni datos: cada aplicación tiene una instancia independiente que no afecta a otras en ejecución, por lo que el motivo principal se ha perdido y ahora cumplen otros roles no menos importantes.&lt;/p&gt;  &lt;p align="justify"&gt;&lt;b&gt;&lt;u&gt;Tipos de DLL&lt;/u&gt;&lt;/b&gt;&lt;/p&gt;  &lt;p align="justify"&gt;Hasta la entrada del .NET Framework, existían cuatro tipos de DLL que, dependiendo de su rol, podían contener una u otra cosa.&lt;/p&gt;  &lt;p align="justify"&gt;· DLL normal de código. Es un conjunto de funciones y funcionalidad más o menos destinada a ser utilizada por otros programas. El propio Windows está construido en base a esta característica: Las DLL kernel32.dll, gdi32.dll y user32.dll forman el núcleo del sistema operativo, al menos del subsistema de Win32/Win64.&lt;/p&gt;  &lt;p align="justify"&gt;· DLL de recursos. Como su nombre indica, sólo contienen recursos y nada de código (o el menos posible). Un recurso puede ser un bitmap, una cadena de texto o la definición de un cuadro de diálogo. Este tipo de DLL es muy útil para construir aplicaciones internacionales en las que las cadenas en cada idioma están almacenadas en una DLL diferente, de modo que cuando se carga el programa podemos indicar qué DLL de recursos cargar, teniendo así nuestra aplicación, de forma casi automática, disponible en todos los idiomas que queramos. El propio Windows lo hace así con las versiones MUI, que incluyen todos los textos y otros elementos en DLL normales pero renombradas con la extensión MUI. Usando este mismo paradigma, podemos tener soporte de temas y resulta mucho más fácil cambiar o actualizar los recursos de una aplicación.&lt;/p&gt;  &lt;p align="justify"&gt;· Contenedores COM, DCOM o ActiveX. Este tipo de DLL apareció relativamente tardíamente, aunque su utilidad es más que destacable, y más que un formato de DLL se trata de un subsistema de Windows que se apoya fuertemente en la DLL para funcionar: en general la mayoría de objetos COM se encuentran almacenados en este tipo de ficheros, si bien muchas veces se les cambia la extensión por OCX, aunque no es imprescindible. &lt;/p&gt;  &lt;p align="justify"&gt;· DLL de extensión. Aunque a primera vista podrían estar incluidas en el primer tipo, la construcción de estas necesita de ciertos cuidados especiales o nos encontraremos con serios problemas en su uso y su creación. Una DLL de extensión &lt;i&gt;extiende&lt;/i&gt; la funcionalidad de alguna aplicación o marco de trabajo o del propio Windows.&lt;/p&gt;  &lt;p align="justify"&gt;Tras la entrada en escena del .NET Framework, los tipos de DLL se han extendido, o más bien los tipos anteriores han aumentado sus roles así como sus nombres y la división clara entre una clase y otra se ha perdido en cierta manera. En general una DLL .NET ya no se llama así, sino que se llama &lt;i&gt;ensamblado&lt;/i&gt; y puede cumplir uno o varios roles anteriores. Los ensamblados &lt;i&gt;normales&lt;/i&gt; ahora contienen una buena cantidad de metadatos que los convierten en un paso más allá de los contenedores COM, no suelen incluir código ensamblador sino que en su interior sólo hay instrucciones MSIL y Windows es incapaz de entenderlas sin el soporte del motor en tiempo de ejecución (&lt;i&gt;runtime&lt;/i&gt;) de .NET.&lt;/p&gt;  &lt;p align="justify"&gt;Evidentemente, la división anterior es solo conceptual, ya que nadie nos impide tener una DLL que contenga código, recursos y extienda un marco de trabajo existente o se inserte como un servidor COM dentro de Windows. No obstante, y en general, los programadores suelen respetar la división.&lt;/p&gt;  &lt;p align="justify"&gt;&lt;b&gt;&lt;u&gt;Usos modernos de una DLL&lt;/u&gt;&lt;/b&gt;&lt;/p&gt;  &lt;p align="justify"&gt;Ya hemos visto algunos en el punto anterior, aunque podemos indicarlos para mayor claridad.&lt;/p&gt;  &lt;p align="justify"&gt;· Interfaz con un Driver. Muchas veces cuando tenemos que acceder a un dispositivo más o menos exótico el fabricante nos suministra una DLL que nosotros usaremos para comunicar nuestra aplicación con el dispositivo. &lt;/p&gt;  &lt;p align="justify"&gt;· Soporte de alguna funcionalidad suministrada por un tercero. Si bien también nos podría dar una biblioteca estática para enlazar con nuestra aplicación, el disponer de una DLL significa que ésta también podrá ser usada en otros lenguajes.&lt;/p&gt;  &lt;p align="justify"&gt;· Soporte de temas. Ponemos todos los recursos de una aplicación en una DLL y el hecho de cambiar de tema supone usar otra DLL con los mismos nombres y tipos de recursos pero diferentes en aspecto.&lt;/p&gt;  &lt;p align="justify"&gt;· Soporte de idiomas. Ponemos todas las cadenas de nuestra aplicación en una DLL y la cargamos en consonancia al idioma seleccionado. Aquí tenemos la desventaja de tener que cargar a mano con &lt;i&gt;LoadString()&lt;/i&gt; todas las cadenas antes de usarlas. Por ejemplo, MFC ayuda en cierta manera a disponer de este sistema de internacionalización, y otras herramientas como C++Builder o el propio .NET las implementan de forma automática, generando y cargando la DLL adecuada en cada caso sin nuestra intervención.&lt;/p&gt;  &lt;p align="justify"&gt;· Ofrecer servicios actualizables. Esta es una gran ventaja, que utiliza el propio Windows y Visual C++ para insertar actualizaciones. Si ponemos cierta funcionalidad en una DLL, cuando queramos actualizarla sólo tendremos que cambiar dicha DLL por otra nueva que conserve el mismo interfaz público (o al menos la parte usada). Es lo que hace Microsoft con el &lt;i&gt;runtime&lt;/i&gt; de Visual C++ cuando se produce alguna actualización de seguridad o corrección de bugs: en Windows Update nos aparece la correspondiente actualización, que &lt;i&gt;sustituirá&lt;/i&gt; (más bien añadirá) la nueva versión al repositorio SXS.&lt;/p&gt;  &lt;p align="justify"&gt;· Modificar el comportamiento del sistema añadiendo &lt;i&gt;ganchos&lt;/i&gt; (&lt;i&gt;hooks&lt;/i&gt;) a Windows. Un ejemplo a esto es insertar una DLL para que actúe de filtro de teclado, dando funcionalidad a las teclas multimedia de nuestro teclado, y una variante es insertar una DLL en otro proceso para tomar el control (o permitir más funcionalidad), que es lo que hace, por ejemplo, Skype (Y no sé para qué).&lt;/p&gt;  &lt;p align="justify"&gt;· Compartir código entre aplicaciones. Aunque a fecha de hoy el ahorro de disco puede ser insignificante, disponer de DLLs con funcionalidad común puede suponer solucionar un bug o realizar algún tipo de mejora de forma simultánea en todas las aplicaciones instaladas que usen dicha DLL. Y por supuesto también está su contrapartida: estropear algo en &lt;i&gt;todas&lt;/i&gt;.&lt;/p&gt;  &lt;p align="justify"&gt;De todos modos, esta lista sólo es una aproximación. Seguro que el lector conoce otros usos o se los puede imaginar.&lt;/p&gt;  &lt;p align="justify"&gt;&lt;b&gt;&lt;u&gt;Requisitos para ser una DLL &amp;quot;estándar&amp;quot;&lt;/u&gt;&lt;/b&gt;&lt;/p&gt;  &lt;p align="justify"&gt;Con esto nos referimos a los requisitos para que una DLL pueda ser utilizada por prácticamente cualquier otro lenguaje de programación, como puede ser el Visual Basic clásico, los lenguajes .NET, Cobol, Dephi, Fortran, etc., e incluso aplicaciones con soporte para ellas como Mathlab y otras.&lt;/p&gt;  &lt;p align="justify"&gt;· El interfaz de programación ha de consistir en funciones globales con el protocolo de llamada &lt;i&gt;__stdcall &lt;/i&gt;de paso de parámetros. Cuando uno hace una llamada a función, el punto de retorno y los parámetros que vamos a usar se guardan en la pila. Dependiendo del protocolo de llamada, la limpieza de la misma corresponderá a quien llama o al llamado, así como el orden en el que los parámetros se guardan en ella también depende del protocolo. Como su nombre indica, &lt;i&gt;__stdcall &lt;/i&gt;especifica un formato que todos los lenguajes deberían entender si quieren comunicarse con el mundo exterior. Hasta donde yo sé no existe ningún lenguaje moderno que pretenda soporte de extensiones y que no entienda el protocolo &lt;i&gt;__stdcall&lt;/i&gt;.&lt;/p&gt;  &lt;p align="justify"&gt;· Si hay variables globales, éstas deben ser de los tipos más estándar posibles, como enteros con un tamaño prefijado. Nada de punteros ni estructuras complejas ni otros elementos dependientes de un compilador en concreto, aunque lo mejor es que no haya ningún tipo de elemento global aparte de las funciones.&lt;/p&gt;  &lt;p align="justify"&gt;· Los parámetros pasados y devueltos han der ser tipos estándar y perfectamente definidos, y debemos huir como de la peste de punteros a &lt;i&gt;void&lt;/i&gt; y burradas similares (aunque a veces son inevitables).&lt;/p&gt;  &lt;p align="justify"&gt;· Nada de clases, ni objetos, ni funciones con extensiones no estándar (por ejemplo, paso variable de parámetros o parámetros por defecto).&lt;/p&gt;  &lt;p align="justify"&gt;· Disponer de un punto de entrada con la firma y la funcionalidad siguiente (Sacado de la MSDN, luego explicaremos esto, cualquiera de las dos firmas nos vale):&lt;/p&gt;  &lt;p align="justify"&gt;&lt;/p&gt;  &lt;div align="justify"&gt;   &lt;pre&gt;BOOL WINAPI DllMain(
HINSTANCE hinstDLL, &lt;span style="color:#008000;"&gt;// handle to DLL module&lt;/span&gt;
DWORD fdwReason, &lt;span style="color:#008000;"&gt;// reason for calling function&lt;/span&gt;
LPVOID lpReserved ); &lt;span style="color:#008000;"&gt;// reserved&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;div align="justify"&gt;
  &lt;pre&gt;int __stdcall DllMain(
HINSTANCE hinstDLL, // handle to DLL module
DWORD fdwReason, // reason for calling function
LPVOID lpReserved ); // reserved&lt;/pre&gt;
&lt;/div&gt;

&lt;p align="justify"&gt;&lt;/p&gt;

&lt;p align="justify"&gt;No obstante, muchas de estas reglas son relajables. La mayoría de lenguajes pueden lidiar con punteros y con estructuras de datos, otros no necesitan para nada el punto de entrada, y otros también trabajan bien con el protocolo de llamada &lt;i&gt;__cdecl&lt;/i&gt;, que es el estándar de C y C++.&lt;/p&gt;

&lt;p align="justify"&gt;Con lo que sí que no suelen poder es con las extensiones de C++ como las clases, los parámetros por defecto o variables, el protocolo de llamada &lt;i&gt;__fastcall&lt;/i&gt; y otras extensiones que muchos compiladores de C++ suministran, como gestión de excepciones y punteros relativos.&lt;/p&gt;

&lt;p align="justify"&gt;Esto no quiere decir que no podamos usar esas cosas en nuestra DLL, que sí podemos, lo que quiere decir es que el interfaz público con el que se debe comunicar la DLL no debe tenerlos. Luego, en nuestro código, podremos usar lo que queramos siempre que no salga fuera. Si usamos excepciones deberemos capturarlas dentro de nuestra DLL y no lanzarlas fuera a no ser que sean del tipo del sistema operativo (y en ese caso tampoco es recomendable).&lt;/p&gt;

&lt;p align="justify"&gt;Aunque pueda parecer extraño, ya que la mayoría de lenguajes modernos implementan clases, las de C++ están prohibidas en la parte pública de una DLL. Eso se debe a la forma en que C++ genera el código. Cuando C++ compila una clase, genera una lista de funciones globales del tipo &amp;quot;MiClase@MiMetodo@&amp;amp;D%&amp;amp;&amp;quot;, que es la forma que tiene el compilador de &lt;i&gt;empaquetar&lt;/i&gt; toda la información sobre el tipo de la función o de la variable. Él sabe cómo se llama el método, y lo llamará de la forma adecuada dentro del código fuente, pero externamente todos esos añadidos no son estándar y suelen variar de compilador a compilador (e incluso entre versiones del mismo), por lo que si exportamos una clase para que sea vista públicamente en nuestra DLL, la DLL exportará dicho listado de funciones. &lt;/p&gt;

&lt;p align="justify"&gt;Realmente se puede hacer, pero luego tenemos que figurarnos a qué método se corresponde cada función y simular el funcionamiento del objeto desde la aplicación que esté usando la DLL a no ser que nuestra aplicación esté escrita en C++ y compilada con el mismo compilador. En ese caso podemos exportar y usar una clase (o cualquier otro tipo de elemento), pero el consumo ha de ser interno. &lt;/p&gt;

&lt;p align="justify"&gt;Y a veces nos encontramos con esta misma situación cuando usamos una DLL de un tercero: éste la ha generado y comprobado con &lt;i&gt;su&lt;/i&gt; compilador y en &lt;i&gt;su&lt;/i&gt; sistema, y luego el usuario final se encuentra con un batiburrillo de estructuras, punteros, punteros a &lt;i&gt;void&lt;/i&gt; y demás zarandajas que le hacen muy difícil usarla en su sistema.&lt;/p&gt;

&lt;p align="justify"&gt;Por eso lo de las reglas.&lt;/p&gt;

&lt;p align="justify"&gt;En una próxima entrada veremos los aspectos prácticos de todo esto.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=151465" width="1" height="1"&gt;</description><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/lenguajes/default.aspx">lenguajes</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/Win32/default.aspx">Win32</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></channel></rss>