<?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 : tips</title><link>http://geeks.ms/blogs/rfog/archive/tags/tips/default.aspx</link><description>Etiquetas: tips</description><dc:language /><generator>CommunityServer 2008.5 SP1 (Build: 31106.3070)</generator><item><title>Cross Threading en MVVM y Windows Phone 8 (y también 7)</title><link>http://geeks.ms/blogs/rfog/archive/2012/12/05/cross-threading-en-mvvm-y-windows-phone-8-y-tambi-233-n-7.aspx</link><pubDate>Wed, 05 Dec 2012 10:42:07 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:207697</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=207697</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/rfog/commentapi.aspx?PostID=207697</wfw:comment><comments>http://geeks.ms/blogs/rfog/archive/2012/12/05/cross-threading-en-mvvm-y-windows-phone-8-y-tambi-233-n-7.aspx#comments</comments><description>&lt;p align="justify"&gt;&amp;#160;&lt;/p&gt;  &lt;p align="justify"&gt;Os cuento una rápida que seguro os va a solucionar un montón de quebraderos de cabeza y que me ha traído loco un rato hasta que me he dado cuenta del pufo.&lt;/p&gt;  &lt;p align="justify"&gt;Todo viene cuando estás usando el patrón MVVM y varías algún dato que se está mostrando en algún componente visual. Todos los tutoriales te dicen que heredes de &lt;i&gt;ObservableCollection&lt;/i&gt; y que implementes el método &lt;i&gt;NotifyPropertyChanged()&lt;/i&gt;. Y te ponen el típico ejemplo:&lt;/p&gt;  &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;event&lt;/span&gt; PropertyChangedEventHandler PropertyChanged;
&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; NotifyPropertyChanged([CallerMemberName] &lt;span class="kwrd"&gt;string&lt;/span&gt; propertyName = &lt;span class="str"&gt;&amp;quot;&amp;quot;&lt;/span&gt;)
{
    var handler = PropertyChanged;
    &lt;span class="kwrd"&gt;if&lt;/span&gt; (&lt;span class="kwrd"&gt;null&lt;/span&gt; != handler)
    {
      handler(&lt;span class="kwrd"&gt;this&lt;/span&gt;, &lt;span class="kwrd"&gt;new&lt;/span&gt; PropertyChangedEventArgs(propertyName));
    }
}&lt;/pre&gt;


&lt;p align="justify"&gt;Hasta aquí nada extraño. Cuando una propiedad cambia su valor, quien quiera que esté observando tu colección se enterará del mismo y actuará en consecuencia. Eso si alguien está observando tu colección, que no siempre ocurre, sobre todo si hay algún &lt;i&gt;converter&lt;/i&gt; de por medio (ya hablaré largo y tendido sobre esto).&lt;/p&gt;

&lt;p align="justify"&gt;Pero el problema viene cuando ese cambio se produce fuera del hilo principal de la aplicación, como suele pasar a poco que estés haciendo algo medianamente serio. No veo yo bloqueando tu aplicación mientras un servicio web o lo que sea se baja lo que se tenga que bajar, aparte de que en Windows Phone la mayoría de llamadas a todo eso son asíncronas.&lt;/p&gt;

&lt;p align="justify"&gt;Si haces un cambio en un hilo que no sea el de la UI, en Windows Phone 7.5 no pasa nada. Simplemente se ejecuta el código y en general tu colección cambia de valor y a veces, sólo a veces, la visualización cambiará. O no.&lt;/p&gt;

&lt;p align="justify"&gt;En Windows Phone 8 ocurre otra cosa no muy diferente. Recibes dos &lt;i&gt;first chance&lt;/i&gt; de dos excepciones diferentes, el IDE no te captura nada a no ser que cambies la configuración de captura de excepciones y el hilo en el que se esté ejecutando el código se muere silenciosamente. Y por supuesto no se cambia nada en la parte visual de tu aplicación.&lt;/p&gt;

&lt;p align="justify"&gt;Vale. Tonto si no pones un bloque &lt;i&gt;try/catch&lt;/i&gt; en cada hilo. Pero aquí estamos hablando de otro combate.&lt;/p&gt;

&lt;p align="justify"&gt;¿Cómo puñetas puedo actualizar eso de forma automática? Es decir, ¿tengo que hacer un &lt;i&gt;BeginInvoke()&lt;/i&gt; cada vez que asigne algo? La respuesta corta es que sí. La larga es lo siguiente.&lt;/p&gt;

&lt;p align="justify"&gt;Primero tienes que crearte una propiedad nueva en la clase App que vas a llamar &lt;i&gt;UiDispatcher&lt;/i&gt; (o como te salga de los OO):&lt;/p&gt;

&lt;p align="justify"&gt;internal static Dispatcher UiDispatcher=Current.RootVisual.Dispatcher;&lt;/p&gt;

&lt;p align="justify"&gt;Y luego cambia el código de arriba por el siguiente:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;event&lt;/span&gt; PropertyChangedEventHandler PropertyChanged;
        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; NotifyPropertyChanged([CallerMemberName] &lt;span class="kwrd"&gt;string&lt;/span&gt; propertyName = &lt;span class="str"&gt;&amp;quot;&amp;quot;&lt;/span&gt;)
        {
            var handler = PropertyChanged;
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (&lt;span class="kwrd"&gt;null&lt;/span&gt; != handler)
            {
                &lt;span class="kwrd"&gt;if&lt;/span&gt; (App.UiDispatcher.CheckAccess())
                    handler(&lt;span class="kwrd"&gt;this&lt;/span&gt;, &lt;span class="kwrd"&gt;new&lt;/span&gt; PropertyChangedEventArgs(propertyName));
                &lt;span class="kwrd"&gt;else&lt;/span&gt;
                    App.UiDispatcher.BeginInvoke(() =&amp;gt; handler(&lt;span class="kwrd"&gt;this&lt;/span&gt;, &lt;span class="kwrd"&gt;new&lt;/span&gt; PropertyChangedEventArgs(propertyName)));
            }
        }  &lt;/pre&gt;


&lt;p align="justify"&gt;Ahora, si os fijáis, si el cambio de vuestra propiedad se realiza dentro del hilo principal, se llamará directamente, y si lo hace desde otro lo hará dentro del &lt;i&gt;Dispatcher&lt;/i&gt; de la UI.&lt;/p&gt;

&lt;p align="justify"&gt;¿Por qué una propiedad y no llamar siempre a &lt;i&gt;Current.RootVisual.Dispatcher&lt;/i&gt;? Pues porque podría interesarnos tener diferentes &lt;i&gt;dispatchers&lt;/i&gt; para otras cosas, pero esa es otra guerra que hay que combatir en otro momento. &lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=207697" width="1" height="1"&gt;</description><category domain="http://geeks.ms/blogs/rfog/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/tips/default.aspx">tips</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/Windows+8/default.aspx">Windows 8</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/Windows+Phone/default.aspx">Windows Phone</category></item><item><title>QT: QFileSystemViewer a partir de una ruta</title><link>http://geeks.ms/blogs/rfog/archive/2012/07/10/qt-qsystemfileviewer-a-partir-de-una-ruta.aspx</link><pubDate>Tue, 10 Jul 2012 15:59:41 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:206036</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=206036</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/rfog/commentapi.aspx?PostID=206036</wfw:comment><comments>http://geeks.ms/blogs/rfog/archive/2012/07/10/qt-qsystemfileviewer-a-partir-de-una-ruta.aspx#comments</comments><description>&lt;p style="margin:0.0px 0.0px 0.0px 0.0px;text-indent:18.0px;font:14.0px Calibri;"&gt;Esto es un “truco” que he encontrado de refilón y lo voy a anotar aquí para que no se me olvide y para goce y disfrute de quien me lea.&lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 0.0px;text-indent:18.0px;font:14.0px Calibri;"&gt;La idea es utilizar el modelo documento/vista de QT para navegar a través del sistema de ficheros, pero solo a partir de una ruta en concreto. &lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 0.0px;text-indent:18.0px;font:14.0px Calibri;"&gt;Si lo utilizamos conforme a la documentación, el árbol de ficheros se verá completo, con todas nuestras carpetas y ficheros. Nosotros queremos que la raíz del árbol sea una ruta cualquiera.&lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 0.0px;text-indent:18.0px;font:14.0px Calibri;min-height:17.0px;"&gt; &lt;/p&gt;
&lt;blockquote&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 0.0px;font:9.5px Consolas;"&gt;QFileSystemModel *model=&lt;span style="color:#103ffb;"&gt;new&lt;/span&gt; QFileSystemModel;&lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 0.0px;font:9.5px Consolas;"&gt;QModelIndex index=model-&amp;gt;setRootPath(“ruta_a_limitar”);&lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 0.0px;font:9.5px Consolas;"&gt;ui-&amp;gt;treeView-&amp;gt;setModel(model);&lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 0.0px;font:9.5px Consolas;"&gt;ui-&amp;gt;treeView-&amp;gt;setRootIndex(index);&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 0.0px;font:9.5px Consolas;min-height:11.0px;"&gt; &lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 0.0px;text-indent:18.0px;font:14.0px Calibri;"&gt;En donde  &lt;em&gt;treeView  &lt;/em&gt;es un QTreeView.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=206036" 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/QT/default.aspx">QT</category></item><item><title>Alfred: Cómo lanza aplicaciones dentro de vmWare</title><link>http://geeks.ms/blogs/rfog/archive/2012/06/26/alfred-c-243-mo-lanza-aplicaciones-dentro-de-vmware.aspx</link><pubDate>Tue, 26 Jun 2012 08:22:49 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:205780</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=205780</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/rfog/commentapi.aspx?PostID=205780</wfw:comment><comments>http://geeks.ms/blogs/rfog/archive/2012/06/26/alfred-c-243-mo-lanza-aplicaciones-dentro-de-vmware.aspx#comments</comments><description>&lt;p style="margin:0.0px 0.0px 0.0px 0.0px;text-indent:18.0px;font:14.0px Cochin;"&gt;&lt;span style="text-decoration:underline;"&gt;&lt;strong&gt;Escenario.&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 0.0px;text-indent:18.0px;font:14.0px Cochin;"&gt;Quieres (o ya tienes) aplicaciones virtualizadas en el Dock. Es decir, tu tienes un programa dentro de una máquina virtual vmWare y quieres lanzarla desde el Dock sin más.&lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 0.0px;text-indent:18.0px;font:14.0px Cochin;"&gt;Para ello, una vez que la máquina virtual está en modo Unity, lanzas la aplicación desde el menú de vmWare y te aparecerá el icono de la misma en el Dock. Ahora sólo tienes que, con el botón derecho del mismo, elegir “Opciones -&amp;gt; Mantener en el Dock”. &lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 0.0px;text-indent:18.0px;font:14.0px Cochin;"&gt;La próxima vez que quieras lanzarla, con hacer clic sobre dicho icono es suficiente para que se abra la máquina virtual y tu programa de forma completamente transparente. Si la máquina está en modo Unity la aplicación se abrirá como una más del MAC. Si no, lo hará dentro de la ventana.&lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 0.0px;text-indent:18.0px;font:14.0px Cochin;"&gt;Vale. &lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 0.0px;text-indent:18.0px;font:14.0px Cochin;min-height:17.0px;"&gt; &lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 0.0px;text-indent:18.0px;font:14.0px Cochin;"&gt;&lt;span style="text-decoration:underline;"&gt;&lt;strong&gt;Problema&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 0.0px;text-indent:18.0px;font:14.0px Cochin;"&gt;Ahora queremos poder lanzar esa aplicación desde un atajo de teclado. Hace tiempo &lt;a href="http://geeks.ms/blogs/rfog/archive/2010/11/13/las-pifias-de-os-x-y-de-office-2011.aspx"&gt;expliqué cómo hacer algo similar&lt;/a&gt; con Automator y una serie de pasos. No sé si funcionará en el caso que nos ocupa, ni me importa mucho ya que ahora tengo instalado Alfred y su Power Pack, que es lo que realmente debería traer OS X de serie…&lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 0.0px;text-indent:18.0px;font:14.0px Cochin;min-height:17.0px;"&gt; &lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 0.0px;text-indent:18.0px;font:14.0px Cochin;"&gt;&lt;span style="text-decoration:underline;"&gt;&lt;strong&gt;Solución&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 0.0px;text-indent:18.0px;font:14.0px Cochin;"&gt;Alfred con el Power Pack tiene la opción de lanzar cualquier aplicación con una combinación de teclas que, creo, se superpone a las del sistema operativo. Hacerlo para cualquier aplicación es completamente trivial, pero para las aplicaciones internas de una máquina virtual es harina de otro costal.&lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 0.0px;text-indent:18.0px;font:14.0px Cochin;"&gt;Mirando aquí y allí, he descubierto que el Dock guarda la configuración de los programas que tiene en su barra aquí: ~/Library/Preferences/com.apple.dock.plist &lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 0.0px;text-indent:18.0px;font:14.0px Cochin;"&gt;Si abres dicho fichero con xCode te encuentras una serie de items numerados. Hay que buscar el que nos ocupa, y en la rama “file-data -&amp;gt; _CFURLString” tenemos lo que nos interesa: la ruta al arhivo que el sistema usa para lanzar el programa que nos interesa.&lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 0.0px;text-indent:18.0px;font:14.0px Cochin;"&gt;Una breve inspección nos dice que, para cada máquina virtual, y dentro de su &lt;em&gt;bumdle&lt;/em&gt;, existe una carpeta llamada “Applications” que contiene un fichero por cada aplicación “exportada” por la máquina virtual.&lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 0.0px;text-indent:18.0px;font:14.0px Cochin;"&gt;Ahora ya sólo nos queda añadir el fichero deseado al lanzador de aplicaciones de Alfred.&lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 0.0px;text-indent:18.0px;font:14.0px Cochin;"&gt;Supongo que los que usáis Parallels tendréis algo equivalente.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=205780" width="1" height="1"&gt;</description><category domain="http://geeks.ms/blogs/rfog/archive/tags/configuraci_26002300_243_3B00_n/default.aspx">configuraci&amp;#243;n</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/tips/default.aspx">tips</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/Apple/default.aspx">Apple</category></item><item><title>Win/MAC: arranque dual y jodimiento de particiones</title><link>http://geeks.ms/blogs/rfog/archive/2011/11/19/win-mac-arranque-dual-y-jodimiento-de-particiones.aspx</link><pubDate>Sat, 19 Nov 2011 12:14:42 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:201768</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=201768</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/rfog/commentapi.aspx?PostID=201768</wfw:comment><comments>http://geeks.ms/blogs/rfog/archive/2011/11/19/win-mac-arranque-dual-y-jodimiento-de-particiones.aspx#comments</comments><description>&lt;p style="margin:0.0px 0.0px 0.0px 0.0px;text-indent:18.0px;font:14.0px Cochin;"&gt;Os lo juro. Estoy hasta los putísimos cojones de Windows, de MAC y de la madre que los parió a todos. El primero por pensarse que todo le pertenece, incluyendo las particiones  HFS+, y el segundo por pensar que todos los usuarios son tontos del culo.&lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 0.0px;text-indent:18.0px;font:14.0px Cochin;"&gt;No tengo muchas ganas de escribir, así que voy a ser bastante escueto.&lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 0.0px;text-indent:18.0px;font:14.0px Cochin;"&gt;Escenario: Windows/MAC con Boot Camp y arranque dual. Como Windows asigna las unidades como le sale de los cojones, entro en el Administrador de Discos y las cambio a los valores que quiero.&lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 0.0px;text-indent:18.0px;font:14.0px Cochin;"&gt;Vale, todo bien en Windows. Inicio OS X y… una de las tres particiones no se carga. Es decir, habiendo cambiado la letra de unidad a &lt;strong&gt;dos&lt;/strong&gt; particiones HFS+ desde Windows, &lt;strong&gt;una&lt;/strong&gt; de ellas luego no se carga desde OS X porque Windows, en su maravilloso afán de poseerlo todo, ha decidido cambiar cierta cadena de las tablas internas del disco por “&lt;span style="color:#29303b;"&gt;Microsoft Basic Data”. Hay que joderse con tomate. ¿No saben reconocer una partición ajena y no tocar nada? Pues parece ser que no, que tienen ganas de joder la marrana.&lt;/span&gt;&lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 0.0px;text-indent:18.0px;font:14.0px Cochin;color:#29303b;"&gt;Bueno, la Utilidad de Discos de OS X se ve incapaz de recuperar la partición. Hala, nueva pérdida de datos. Cuatro máquinas virtuales y un montón de descargas.&lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 0.0px;text-indent:18.0px;font:14.0px Cochin;color:#29303b;"&gt;***&lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 0.0px;text-indent:18.0px;font:14.0px Cochin;color:#29303b;"&gt;Pues no, hay solución. Está &lt;a href="http://steelpangolin.wordpress.com/2009/03/15/invalid-bs_jmpboot-in-boot-block-000000/"&gt;aquí&lt;/a&gt;. Otro &lt;em&gt;geek&lt;/em&gt; de la más alta alcurnia se ha encontrado con el mismo problema y ha creado una aplicación en Python para solucionar el problema. Lo único que hace es cambiar dicha cadena por su valor por defecto. Y entonces OS X reconoce la partición como suya y la monta.&lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 0.0px;text-indent:18.0px;font:14.0px Cochin;color:#29303b;"&gt;Olé sus cojones.&lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 0.0px;text-indent:18.0px;font:14.0px Cochin;color:#29303b;"&gt;Os cuento cómo hacerlo.&lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 0.0px;text-indent:18.0px;font:14.0px Cochin;color:#29303b;"&gt;***&lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 0.0px;text-indent:18.0px;font:14.0px Cochin;color:#29303b;"&gt;Desmonta el disco completo en donde esté la partición afectada. Luego graba el fichero &lt;a href="http://bat-country.us/code/GPTools/trunk/gpt_surgeon.py?view=markup"&gt;&lt;em&gt;gpt_surgeon.py&lt;/em&gt;&lt;/a&gt; en disco (ojo con grabar el html y no el contenido del mismo). Aquí viene cuando Apple piensa que somos imbéciles o así. Tu grabas un archivo, que te lo pone como texto de lectura escritura. Pero tu lo quieres de ejecución, porque si no ya puedes darle de sopapos porque se negará a correr.&lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 0.0px;text-indent:18.0px;font:14.0px Cochin;color:#29303b;"&gt;Hay que añadir el bit de ejecución. ¿Cómo? Ahí está el problema. Desde la interfaz gráfica no se puede, porque CMD-I sólo te dejar cambiar entre lectura y escritura, pero no ejecución.&lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 0.0px;text-indent:18.0px;font:14.0px Cochin;color:#29303b;"&gt;Quizás haya algún botón por algún lado para activarlo, pero no lo he encontrado, así que tienes que abrir una ventana de terminal y cambiarlo &lt;em&gt;ala &lt;/em&gt;UNIX: &lt;strong&gt;“chmod u+x gpt_surgeon.py”&lt;/strong&gt;. Claro, puede que algún imbécil siga la secuencia desde el Finder y sea capaz de cambiarle los permisos a un troyano. En fin, viva la ergonomía y usabilidad maqueras.&lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 0.0px;text-indent:18.0px;font:14.0px Cochin;color:#29303b;"&gt;Luego sigues la secuencia explicada en el enlace de arriba:&lt;/p&gt;
&lt;ul style="list-style-type:disc;"&gt;
&lt;li style="margin:0.0px 0.0px 0.0px 0.0px;font:14.0px Cochin;color:#29303b;"&gt;./gpt_surgeon.py list /dev/disk&amp;lt;n&amp;gt;, en donde &amp;lt;n&amp;gt; es el disco &lt;em&gt;malo&lt;/em&gt;.&lt;/li&gt;
&lt;li style="margin:0.0px 0.0px 0.0px 0.0px;font:14.0px Cochin;color:#29303b;"&gt;Localiza la partición jodida, en la que debe aparecer el infame texto de “Microsoft Basic Data”.&lt;/li&gt;
&lt;li style="margin:0.0px 0.0px 0.0px 0.0px;font:14.0px Cochin;color:#29303b;"&gt;sudo ./gpt_surgeon.py repair /dev/disk&amp;lt;n&amp;gt; &amp;lt;y&amp;gt;, en donde &amp;lt;y&amp;gt; es la partición rota. &lt;/li&gt;
&lt;li style="margin:0.0px 0.0px 0.0px 0.0px;font:14.0px Cochin;color:#29303b;"&gt;Al poco, OS X (o el script) montará todas las unidades, habiendo reparado la estropeada.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 0.0px;text-indent:18.0px;font:14.0px Cochin;color:#29303b;"&gt;Y ya está, esta ha sido la crónica del día de hoy. Cagontó…&lt;/p&gt;
&lt;p style="margin:0.0px 0.0px 0.0px 0.0px;font:12.0px Cochin;color:#29303b;min-height:14.0px;"&gt; &lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=201768" 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/chapuzas/default.aspx">chapuzas</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/bugs/default.aspx">bugs</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/tips/default.aspx">tips</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>OS X Lion: Activar la repetición de teclas</title><link>http://geeks.ms/blogs/rfog/archive/2011/07/31/os-x-lion-activar-la-repetici-243-n-de-teclas.aspx</link><pubDate>Sun, 31 Jul 2011 18:38:17 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:198604</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=198604</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/rfog/commentapi.aspx?PostID=198604</wfw:comment><comments>http://geeks.ms/blogs/rfog/archive/2011/07/31/os-x-lion-activar-la-repetici-243-n-de-teclas.aspx#comments</comments><description>&lt;p&gt;Sin muchas ganas de escribir una nueva entrada, voy a poner algo interesante que corrige una de las cagadas de OS X Lion: la repetición de las teclas que llevan caracteres especiales.&lt;/p&gt;
&lt;p&gt;Como os comenté en la &lt;a href="http:///blogs/rfog/archive/2011/07/23/os-x-lion-mucho-rugido-y-pocas-nueces.aspx"&gt;entrada anterior,&lt;/a&gt; Apple la había cagado a base de bien con el tema de la repetición de teclas. Supongo que para un usuario Ruso o Báltico, la cosa puede resultarle interesante, pero no para la mayoría del resto del mundo.&lt;/p&gt;
&lt;p&gt;Si la opción fuera configurable no habría problema: se cambia y ya está, pero no lo es, o al menos no lo es de forma sencilla ya que no aparece por ningún lado en la configuración.&lt;/p&gt;
&lt;p&gt;Sin embargo sí que existe una forma de volver la cosa a su estado original, y es mediante un comando tecleado en el terminal de OS.&lt;/p&gt;
&lt;p&gt;Abrís la aplicación de terminal (tal y como se escribe), y pegáis el texto:&lt;/p&gt;
&lt;p style="color:#333333;font-family:Helvetica, Arial, sans-serif;font-size:15px;line-height:20px;"&gt;&lt;/p&gt;
&lt;blockquote&gt;
  &lt;p&gt;&lt;font color="#333333" face="Helvetica, Arial, sans-serif"&gt;&lt;span style="font-size:15px;line-height:20px;"&gt;defaults write -g ApplePressAndHoldEnabled -bool false&lt;/span&gt;&lt;/font&gt;&lt;br /&gt;&lt;/p&gt;

  &lt;p&gt;&lt;font color="#333333" face="Helvetica, Arial, sans-serif"&gt;&lt;br /&gt;&lt;/font&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Y pulsáis enter. Ya está cambiado. No sé si es necesario reiniciar o cerrar la sesión abierta porque simplemente lo piqué y seguí con el MAC encendido y no tuve oportunidad de comprobarlo hasta que reinicié al día siguiente.&lt;/p&gt;
&lt;p&gt;Y es que, a veces, sólo a veces, esas webs sensacionalistas pro Apple sirven para algo, ya que de esto me enteré &lt;a href="http://www.applesfera.com/curiosidades/os-x-lion-nueva-manera-de-acentuar-palabras-e-introducir-simbolos"&gt;aquí&lt;/a&gt;.&lt;/p&gt;
&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=198604" 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/tips/default.aspx">tips</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/Apple/default.aspx">Apple</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>El RFOG se renueva, por dentro y por fuera</title><link>http://geeks.ms/blogs/rfog/archive/2010/12/02/el-rfog-se-renueva-por-dentro-y-por-fuera.aspx</link><pubDate>Thu, 02 Dec 2010 20:40:45 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:185517</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=185517</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/rfog/commentapi.aspx?PostID=185517</wfw:comment><comments>http://geeks.ms/blogs/rfog/archive/2010/12/02/el-rfog-se-renueva-por-dentro-y-por-fuera.aspx#comments</comments><description>&lt;p&gt;Sí, pese a lo que dijo sobre su MAC, al final se ha comprado un PC que sin ser lo último de lo último, tiene su cosa. El MAC está bien, pero le echa a faltar muchas cosas, muchos programas y otros temas, así que, al final, en lugar de comprarse un MAC PRO, se ha decidido por un clónico.&lt;/p&gt;  &lt;p&gt;Si os preguntáis qué le ha pasado con su ordenador viejo, no lo hagáis directamente a él, porque va a coger un cabreo de cojones y posiblemente os deje con la palabra en la boca… si no os suelta alguna fresca.&lt;/p&gt;  &lt;p&gt;Básicamente su QUAD con 8 GB de RAM se ha quedado en la empresa. Para evitar jaleos y tener la fiesta en paz, ha decidido que no vale la pena batallar por cosa tan nimia (Si no lo sabíais, el RFOG ha pasado, por ordeno y mando, de trabajar en su casa a tener que ir, todos los días, a una empresa, gastando por ello al menos hora u hora y media más de su vida por las mismas prestaciones económicas, y de hecho sigue preguntándose por qué no se ha ido sin más... Corramos un estúpido velo sobre el tema y dejemos la cosa como está.&lt;/p&gt;  &lt;p&gt;Bueno, el nuevo ordenador del RFOG está compuesto por una placa Gigabyte (Modelo P55A-UD4) que tiene hasta tres chipsets para discos. Uno para el eSata, otro para los SATA II normales y un tercero para dos discos SATA III. Aparte la placa tiene FireWire 400. Ahí es nada, y también ahí es nada el tiempo que tarda toda la rutina del POST, de hecho más tiempo que el necesario para arrancar su Windows.&lt;/p&gt;  &lt;p&gt;Esa placa ejecuta un Core i7 870 a 2.93 GHz que tiene cuatro núcleos dobles con HyperThreading, lo que suman 8. Y bien bonitos que se ven en el Administrador de Tareas. Y también, de momento, no les ha visto el culo, porque no suben del 40% total de tiempo de proceso.&lt;/p&gt;  &lt;p&gt;La idea original era ponerle 16GB de RAM, pero al final sólo pudo disponer de 4 porque no le pudieron encontrar módulos de 4GB, aunque le han dicho que en cuanto los consigan lo avisan y se los cambian. De todos modos, 8GB ya son gigas para lo que el RFOG quiere.&lt;/p&gt;  &lt;p&gt;La tarjeta de vídeo es una ATI HD6850. El rendimiento es tal que ni el StarCraft II ni el Civilization V a plena resolución hacen que la el ventilador de la misma se revolucione. Ahí es nada. De hecho, apenas nota que tiene algunas cosas con vmWare en modo Unity (que ya es decir).&lt;/p&gt;  &lt;p&gt;Luego están los discos. Un SATA II de 1 TB normalito como disco de datos y de seguridad. Y cuatro discos SSD de 64GB en dos RAID 0. Sí, lo que oís, los discos valen más que el resto del ordenador.&lt;/p&gt;  &lt;p&gt;Pero ¡chico!, cómo van. Y eso que no son de los más rapiditos que hay, que si no… El arranque de Windows hasta mostrar el escritorio es unos 10 segundos. La tasa de transferencia en copia entre las dos agrupaciones RAID es de unos 220-230 MB/s sostenida (unos 40 GB de una tacada).&lt;/p&gt;  &lt;p&gt;A todo eso ha añadido a su ya existente monitor de 24”… otro más. Y como el primero tiene resolución de 1920x1200, el nuevo también la tiene (los modernos traen una de 1920x1080, quizás para poder bajar precios). Y el RFOG se pierde entre tanta pantalla.&lt;/p&gt;  &lt;p&gt;***&lt;/p&gt;  &lt;p&gt;Eso en cuanto al hardware. Respecto al software la cosa es algo más normal. El SATA II tiene dos particiones, en una de ellas está su trabajo y en la otra se mantienen las copias de seguridad de los otros dos conjuntos RAID, que el RFOG no se fía mucho ni de los SSD ni de los RAID. Relativamente amargas experiencias ha tenido con los últimos.&lt;/p&gt;  &lt;p&gt;En uno de los RAID está Windows 7 x64 al completo con algunos programas más, entre ellos vmWare y Office. En el otro hay almacenadas varias máquinas virtuales, en donde se han instalado diferentes programas. En una de ellas está Visual Studio 2010, y en otra, Visual Studio 2008SP1 con los SDKs embebidos. Y así. Esas dos son Windows 7 Ultimate x86 con 3GB de RAMy 2 procesadores con 2 cores, y se pueden tener ambas abiertas sin mucha penalización de rendimiento (en su i7, claro, y más cuando tenga 16GB de RAM).&lt;/p&gt;  &lt;p&gt;Y la idea es mantener limpio su HOST e ir intercambiando las máquinas virtuales según necesidad. Su nueva máquina lo da, y de momento la cosa está funcionando bien, con algunos detalles que está puliendo a ratos. Puede poner accesos directos a los programas en su barra de tareas como si una aplicación no virtualizada se tratara, y cuando la lanza primero se abre la máquina virtual en modo Unity y luego se lanza la aplicación. &lt;/p&gt;  &lt;p&gt;El único problema es que Visual Studio no se lleva bien con los proyectos situados en carpetas de red, aunque sean compartidas a nivel de vmWare, así que ha metido todos sus proyectos en un disco duro virtual de Windows (VHD) y lo ha añadido a la configuración de la máquina virtual.&lt;/p&gt;  &lt;p&gt;Un detalle del que se ha dado cuenta es que la máquina virtual, salvo el acceso a video, es sensiblemente más rápida que la real. Ignora si eso se debe a que es de 32 bits en lugar de 64, o a que al estar el disco comprimido sobre un SSD la rapidez es impresionante…&lt;/p&gt;  &lt;p&gt;Evidentemente todo esto es a nivel particular. A nivel de curro la cosa sigue como antes. (Bueno, mucho peor, pero sigue haciendo proyectos interesantes, que quizás sea lo único que lo mantenga apegado a él).&lt;/p&gt;  &lt;p&gt;***&lt;/p&gt;  &lt;p&gt;Bueno, ya para finalizar, la idea original era &lt;i&gt;hackintoshear&lt;/i&gt; la placa base (que se puede, es una de las que tienen el parche de la BIOS) para instalarse un Snow Leopard en nativo y virtualizar todos sus Windows, pero una vez que tuvo delante de sí el PC… se le quitaron las ganas de hacerlo. Es muy posible que en un arranque de aburrimiento lo intente, o que se instale una VM pirateada. &lt;/p&gt;  &lt;p&gt;Ya veremos.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=185517" 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/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/tips/default.aspx">tips</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/hardware/default.aspx">hardware</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>¡Los diccionarios personalizados de Visual Assist no funcionan con Visual Studio 2010!</title><link>http://geeks.ms/blogs/rfog/archive/2010/09/16/161-los-diccionarios-personalizados-de-visual-assist-no-funcionan-con-visual-studio-2010.aspx</link><pubDate>Thu, 16 Sep 2010 16:42:00 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:182048</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=182048</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/rfog/commentapi.aspx?PostID=182048</wfw:comment><comments>http://geeks.ms/blogs/rfog/archive/2010/09/16/161-los-diccionarios-personalizados-de-visual-assist-no-funcionan-con-visual-studio-2010.aspx#comments</comments><description>&lt;p&gt;Si ten&amp;eacute;is esta estupenda herramienta de &lt;a href="http://www.wholetomato.com/"&gt;Whole Tomato&lt;/a&gt; seguro que os puede pasar lo que a m&amp;iacute;. En su WEB tienen bien explicado, y clarito, c&amp;oacute;mo instalar otros diccionarios aparte del ingl&amp;eacute;s que viene de serie.&lt;/p&gt;
&lt;p align="justify"&gt;Los diccionarios sirven para que el programa encuentre errores ortogr&amp;aacute;ficos en los comentarios y otras partes. Yo suelo escribirlo todo en ingl&amp;eacute;s cuando pico c&amp;oacute;digo (en mi macarr&amp;oacute;nico, inigualable e incre&amp;iacute;blemente culto ingl&amp;eacute;s &amp;ndash; &amp;iexcl;ejem!), pero hay proyectos que los pongo en castellano por el destino de los mismos.&lt;/p&gt;
&lt;p align="justify"&gt;Lo m&amp;aacute;s curioso es que, una vez instalados, los diccionarios funcionan en Visual Studio 2008 y anteriores pero no en la versi&amp;oacute;n 2010.&lt;/p&gt;
&lt;p align="justify"&gt;Podemos encontrar en la WEB de Whole Tomato la forma de instalarlos, &lt;a href="https://www.wholetomato.com/products/features/misspelled.asp"&gt;aqu&amp;iacute;&lt;/a&gt;. Pero est&amp;aacute; en ingl&amp;eacute;s, as&amp;iacute; que voy a explicarlo en castellano.&lt;/p&gt;
&lt;p align="justify"&gt;La instalaci&amp;oacute;n de un diccionario requiere que nos bajemos el mismo del proyecto &lt;a href="http://lingucomponent.openoffice.org/"&gt;Open Office&lt;/a&gt; y nos quedemos con el archivo .aff y el .dic. Para castellano son &amp;ldquo;es_ES.aff&amp;rdquo; y &amp;ldquo;es_ES.dic&amp;rdquo;. Ahora tenemos que poner estos archivos en la carpeta &amp;ldquo;C:\Program Files (x86)\Visual Assist X\Dict&amp;rdquo; si nuestro Windows es de 64 bits o en la carpeta &amp;ldquo;C:\Program Files\Visual Assist X\Dict&amp;rdquo; si es de 32. Como mis Windows est&amp;aacute;n en ingl&amp;eacute;s, si los vuestros est&amp;aacute;n en castellano, ten&amp;eacute;is que sustitur &amp;ldquo;Program Files&amp;rdquo; por &amp;ldquo;Archivos de programa&amp;rdquo;.&lt;/p&gt;
&lt;p align="justify"&gt;Una vez que teng&amp;aacute;is ah&amp;iacute; los dos ficheros y reiniciemos Visual Studio, ya podremos usar palabras en el idioma instalado sin que Visual Assist proteste poni&amp;eacute;ndonos la rayita roja por debajo de la palabra faltona. No hace falta decir que si no queremos un idioma, con borrar sus correspondientes ficheros .aff y .dic todo resuelto.&lt;/p&gt;
&lt;p align="justify"&gt;&lt;b&gt;En Visual Studio 2010 no funcionan.&lt;/b&gt; Esa es la forma est&amp;aacute;ndar de hacerlo, pero si tenemos la &amp;uacute;ltima versi&amp;oacute;n de Visual Studio nos encontramos con que los diccionarios a&amp;ntilde;adidos no funcionan. No, no es un bug del programa, es que han cambiado la localizaci&amp;oacute;n de los mismos. Si queremos tenerlos disponibles tambi&amp;eacute;n para la versi&amp;oacute;n 2010, debemos colocarlos en nuestro &lt;i&gt;profile&lt;/i&gt;:&lt;/p&gt;
&lt;p align="justify"&gt;&amp;middot; C:\Users\&amp;lt;usuario&amp;gt;\AppData\Roaming\VisualAssist\Dict&lt;/p&gt;
&lt;p align="justify"&gt;Fijaros que ten&amp;eacute;is que cambiar &amp;lt;usuario&amp;gt; por el nombre de vuestro usuario, y que la carpeta &amp;ldquo;AppData&amp;rdquo; es oculta.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=182048" 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/tips/default.aspx">tips</category></item><item><title>Detectando fugas de memoria en Visual C++</title><link>http://geeks.ms/blogs/rfog/archive/2010/07/01/detectando-fugas-de-memoria-en-visual-c.aspx</link><pubDate>Thu, 01 Jul 2010 11:21:00 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:178742</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=178742</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/rfog/commentapi.aspx?PostID=178742</wfw:comment><comments>http://geeks.ms/blogs/rfog/archive/2010/07/01/detectando-fugas-de-memoria-en-visual-c.aspx#comments</comments><description>&lt;p align="justify"&gt;A veces nos encontramos con que nuestro programa &amp;ldquo;chorrea&amp;rdquo; memoria, y hasta hace poco tiempo no hab&amp;iacute;a nada tan terrible para un programador como encontrar d&amp;oacute;nde se produc&amp;iacute;a el problema, m&amp;aacute;xime cuando se trataba de aplicaciones con m&amp;uacute;ltiples hilos. &lt;/p&gt;
&lt;p align="justify"&gt;Hubo una &amp;eacute;poca en la que incluso hab&amp;iacute;a herramientas de terceros y analizadores de c&amp;oacute;digo para encontrar este tipo de problemas. Pero recientemente (creo que a partir de la versi&amp;oacute;n 2005 de Visual C++), Microsoft a&amp;ntilde;adi&amp;oacute; una serie de utilidades a la compilaci&amp;oacute;n Debug para detectar estos errores de forma casi inmediata.&lt;/p&gt;
&lt;p align="justify"&gt;Visual C++ 2005 cre&amp;oacute; la t&amp;eacute;cnica, y Visual C++ 2008 la perfeccion&amp;oacute;. Y por supuesto Visual C++ la mantiene. &lt;/p&gt;
&lt;p align="justify"&gt;Veamos un ejemplo. &amp;iquest;Qu&amp;eacute; tiene de malo este c&amp;oacute;digo fuente tan sencillo?&lt;/p&gt;
&lt;pre&gt;&lt;span style="color:#0000ff;"&gt;class&lt;/span&gt; Elemento
{
    &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt;:
    &lt;span style="color:#0000ff;"&gt;char&lt;/span&gt; A,B,C,D;

};

&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; _tmain(&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;argc&lt;/span&gt;, _TCHAR* &lt;span style="color:#0000ff;"&gt;argv&lt;/span&gt;[])
{
    Elemento *e=&lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Elemento();

    &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; 0;
}&lt;/pre&gt;
&lt;p align="justify"&gt;Es evidente m&amp;aacute;s all&amp;aacute; de toda duda que no hemos liberado &lt;i&gt;e&lt;/i&gt;. Este es un caso trivial, porque cuando salgamos del programa el espacio de direcciones se limpiar&amp;aacute; y no pasar&amp;aacute; nada. Pero imaginaros esa asignaci&amp;oacute;n en un bucle dentro de un programa destinado a estar horas y horas en ejecuci&amp;oacute;n. &lt;/p&gt;
&lt;p align="justify"&gt;Llega un momento en que ocupa toda la memoria disponible y revienta. Y lo peor es que el error que nos d&amp;eacute; ser&amp;aacute; tan cr&amp;iacute;ptico y tan extra&amp;ntilde;o que, si no miramos el programa corriendo en el administrador de tareas no nos daremos cuenta. Y a veces ni as&amp;iacute; si el crecimiento del uso de la memoria es lento. &lt;/p&gt;
&lt;p align="justify"&gt;Adem&amp;aacute;s, en cada m&amp;aacute;quina el error ser&amp;aacute; diferente, e incluso en la misma m&amp;aacute;quina dar&amp;aacute; diferentes errores dependiendo del uso del programa y del propio sistema (hablamos de excepciones extra&amp;ntilde;as con mensajes extra&amp;ntilde;os e incluso mostrando texto corrupto).&lt;/p&gt;
&lt;p align="justify"&gt;Imaginaros ahora que os dan un programa de cien mil l&amp;iacute;neas que haya pasado por cinco o seis programadores, algunos de ellos malos y otros peores, que el programa tenga fugas de memoria y que te lo asignen a ti para solucionarlos.&lt;/p&gt;
&lt;p align="justify"&gt;No, no vale pegarse un tiro ni prenderle fuego al ordenador o a la empresa.&lt;/p&gt;
&lt;p align="justify"&gt;***&lt;/p&gt;
&lt;p align="justify"&gt;Es much&amp;iacute;simo m&amp;aacute;s f&amp;aacute;cil que todo eso. Si nuestro programa est&amp;aacute; hecho en MFC tan s&amp;oacute;lo tendremos que recompilarlo con Visual Studio 2008 o siguiente, ejecutarlo un rato desde el IDE y cerrarlo.&lt;/p&gt;
&lt;p align="justify"&gt;Si no usa MFC y s&amp;oacute;lo usa Win32 u otras librer&amp;iacute;as, debemos a&amp;ntilde;adir varias cosas al mismo. Abajo el nuevo c&amp;oacute;digo.&lt;/p&gt;
&lt;pre&gt;#&lt;span style="color:#0000ff;"&gt;define&lt;/span&gt; _CRTDBG_MAP_ALLOC
#&lt;span style="color:#0000ff;"&gt;include&lt;/span&gt; &amp;lt;stdlib.h&amp;gt;
#&lt;span style="color:#0000ff;"&gt;include&lt;/span&gt; &amp;lt;crtdbg.h&amp;gt;

&lt;span style="color:#0000ff;"&gt;class&lt;/span&gt; Elemento
{
    &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt;:
    &lt;span style="color:#0000ff;"&gt;char&lt;/span&gt; A,B,C,D;

};

&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; _tmain(&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;argc&lt;/span&gt;, _TCHAR* &lt;span style="color:#0000ff;"&gt;argv&lt;/span&gt;[])
{
    Elemento *e=&lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Elemento();

    _CrtDumpMemoryLeaks();
    &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; 0;
}&lt;/pre&gt;
&lt;p align="justify"&gt;Hemos incluido unos ficheros cabecera y en el punto de salida hemos hecho una llamada a la funci&amp;oacute;n _CrtDumpMemoryLeaks(). La salida de la ventana Output (from Debug) tras una ejecuci&amp;oacute;n es la siguiente:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p align="justify"&gt;[&amp;hellip; texto omitido &amp;hellip;] &lt;br /&gt;&amp;#39;fugas_memoria.exe&amp;#39;: Loaded &amp;#39;C:\Windows\SysWOW64\msvcr100d.dll&amp;#39;, Symbols loaded. &lt;br /&gt;Detected memory leaks! &lt;br /&gt;Dumping objects &amp;ndash;&amp;gt; &lt;br /&gt;{107} normal block at 0x00695E30, 4 bytes long. &lt;br /&gt;Data: &amp;lt; &amp;gt; 00 00 00 00 &lt;br /&gt;Object dump complete. &lt;br /&gt;The program &amp;#39;[716] fugas_memoria.exe: Native&amp;#39; has exited with code 0 (0x0).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p align="justify"&gt;Nos fijamos en algunas l&amp;iacute;neas que nos dicen que ha habido fugas de memoria en un bloque de 4 bytes (que se corresponden a los cuatro &lt;i&gt;char&lt;/i&gt; que hemos indicado en la clase). Mola, &amp;iquest;no?&lt;/p&gt;
&lt;p align="justify"&gt;Bueno, ya sabemos que tenemos una fuga de memoria, pero no sabemos qui&amp;eacute;n la est&amp;aacute; generando. Vamos a averiguarlo.&lt;/p&gt;
&lt;p align="justify"&gt;Lo primero es fijarnos en la l&amp;iacute;nea&lt;/p&gt;
&lt;blockquote&gt;
&lt;p align="justify"&gt;{107} normal block at 0x00695E30, 4 bytes long&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p align="justify"&gt;y en el n&amp;uacute;mero que hay entre corchetes: 107. Ese es el n&amp;uacute;mero de bloque de memoria que no est&amp;aacute; siendo liberado. Una vez que sabemos qu&amp;eacute; bloque es, debemos relanzar la aplicaci&amp;oacute;n pero esta vez en lugar de ejecutarla con F5 o con Debug -&amp;gt; Run, ejecutamos un solo paso para que se nos quede en el punto de entrada inicial pulsando F11 o Debug -&amp;gt; Step Into. Tambi&amp;eacute;n podemos poner un punto de interrupci&amp;oacute;n.&lt;/p&gt;
&lt;p align="justify"&gt;Una vez hecho esto, abrimos una ventana de Watch (Inspecci&amp;oacute;n) y a&amp;ntilde;adimos la variable &lt;/p&gt;
&lt;blockquote&gt;
&lt;p align="justify"&gt;{,,msvcr100d.dll}_crtBreakAlloc&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p align="justify"&gt;a inspeccionar. La parte &amp;ldquo;msvcr100d.dll&amp;rdquo; depender&amp;aacute; de la versi&amp;oacute;n del compilador que estemos usando. En general ser&amp;aacute; &amp;ldquo;msvcr71d.dll&amp;rdquo; para 2003, &amp;ldquo;msvcr80d.dll&amp;rdquo; para 2005 y &amp;ldquo;msvcr80d.dll&amp;rdquo; para 2008 , aparte de la expuesta para 2010.&lt;/p&gt;
&lt;p align="justify"&gt;Ahora ponemos 107 como valor, ejecutamos el programa y&amp;hellip; &amp;iexcl;Nos saltar&amp;aacute; una excepci&amp;oacute;n! Le damos a &amp;ldquo;break&amp;rdquo; y se nos abre un fichero de c&amp;oacute;digo fuente de las tripas del runtime de C/C++. Para ir a donde nos interesa, abrimos la ventana de &amp;ldquo;Call Stack&amp;rdquo; y buscamos nuestro c&amp;oacute;digo fuente entre la pila de llamadas.&lt;/p&gt;
&lt;p align="justify"&gt;&amp;iexcl;Y all&amp;iacute; estar&amp;aacute; el new o el malloc() que nunca se libera! &amp;iexcl;Hemos encontrado la fuga!&lt;/p&gt;
&lt;p align="justify"&gt;***&lt;/p&gt;
&lt;p align="justify"&gt;A simple vista parece algo lioso, pero os puedo asegurar que cada vez que explico esto en alguna de las empresas por las que voy se notan los suspiros de alivio de todo el departamento de desarrollo y vuelven las sonrisas.&lt;/p&gt;
&lt;p align="justify"&gt;Si nuestra aplicaci&amp;oacute;n est&amp;aacute; hecha en MFC todav&amp;iacute;a es m&amp;aacute;s f&amp;aacute;cil porque la mitad de cosas ya vienen predefinidas (de ah&amp;iacute; esa extra&amp;ntilde;a definici&amp;oacute;n de &amp;ldquo;DEBUG_NEW&amp;rdquo; que hay por los ficheros de c&amp;oacute;digo fuente).&lt;/p&gt;
&lt;p align="justify"&gt;Las apuestas pueden subir cuando el error es aleatorio, pero siempre ser&amp;aacute; m&amp;aacute;s f&amp;aacute;cil as&amp;iacute; que sin ayuda. Adem&amp;aacute;s, existen &lt;i&gt;trucos&lt;/i&gt; como poner peri&amp;oacute;dicamente llamadas al volcado de las fugas, aparte de que hay m&amp;aacute;s opciones para la detecci&amp;oacute;n, algunas de ellas no documentadas porque vienen de la propia experiencia personal.&lt;/p&gt;
&lt;p align="justify"&gt;Todo esto que he explicado aqu&amp;iacute; est&amp;aacute; contado en varios lugares de la MSDN, y hay m&amp;aacute;s opciones y variaci&amp;oacute;n, de hecho una b&amp;uacute;squeda de &amp;ldquo;memory leak&amp;rdquo; arroja bastantes resultados.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=178742" 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/tips/default.aspx">tips</category></item><item><title>Qué hacer cuando a Visual C++ se le va la pinza en el editor de diálogos</title><link>http://geeks.ms/blogs/rfog/archive/2010/02/17/qu-233-hacer-cuando-a-visual-c-se-le-va-la-pinza-en-el-editor-de-di-225-golos.aspx</link><pubDate>Wed, 17 Feb 2010 12:25:00 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:167421</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=167421</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/rfog/commentapi.aspx?PostID=167421</wfw:comment><comments>http://geeks.ms/blogs/rfog/archive/2010/02/17/qu-233-hacer-cuando-a-visual-c-se-le-va-la-pinza-en-el-editor-de-di-225-golos.aspx#comments</comments><description>&lt;p align="justify"&gt;Supongo que le habr&amp;aacute; pasado a m&amp;aacute;s de uno, que est&amp;aacute; haciendo cosas en el editor de di&amp;aacute;logos de Visual C++ y de repente se le va la pinza y deja de funcionar como debe, a veces dando un error que no es un error.&lt;/p&gt;
&lt;p align="justify"&gt;Esto normalmente se debe a que hay algo mal en el c&amp;oacute;digo fuente que impide al parser actuar debidamente. Quiz&amp;aacute;s hemos a&amp;ntilde;adido una entrada mal en el mapa de mensajes, o en el DDX o simplemente el fichero de recursos est&amp;eacute; mal.&lt;/p&gt;
&lt;p align="justify"&gt;Pero otras veces simplemente pasa, como ahora mismo. En este caso concreto ha sido a&amp;ntilde;adiendo una variable para un control: he introducido el nombre (un nombre correcto) y me ha dicho que la sintaxis estaba mal (ejem) y a partir de ese momento la opci&amp;oacute;n de a&amp;ntilde;adir variable se ha ido de vacaciones&amp;hellip;&lt;/p&gt;
&lt;p align="justify"&gt;La soluci&amp;oacute;n habitual es llamar a &amp;ldquo;Build -&amp;gt; Clean Solution&amp;rdquo;, pero eso tampoco termina de funcionar, as&amp;iacute; que a veces tenemos que pasar por hacerlo todo a mano&amp;hellip;&lt;/p&gt;
&lt;p align="justify"&gt;Pues bien, en este caso concreto, cerramos Visual Studio, nos vamos a la carpeta del proyecto insultante y borramos el fichero de proyecto con la extensi&amp;oacute;n del nombre de red de nuestra m&amp;aacute;quina (no el .vcproj, si borramos ese la cagamos a base de bien, sino el .vcproj.&amp;lt;host&amp;gt;), y &lt;b&gt;el fichero .aps&lt;/b&gt;. A partir de ese momento todo deber&amp;iacute;a volver a funcionar bien. Tambi&amp;eacute;n podr&amp;iacute;amos, ya de paso, borrar la carpeta DEBUG tanto de la del proyecto como de la soluci&amp;oacute;n, as&amp;iacute; como el .NCB y el .SUO de la soluci&amp;oacute;n, pero no es necesario.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=167421" 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/tips/default.aspx">tips</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/MFC/default.aspx">MFC</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>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>Vídeo de introducción al MFC Feature Pack de Microsoft en Microsoft</title><link>http://geeks.ms/blogs/rfog/archive/2009/06/17/v-237-deo-de-introducci-243-n-al-mfc-feature-pack-de-microsoft-en-microsoft.aspx</link><pubDate>Wed, 17 Jun 2009 13:47:00 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:150640</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=150640</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/rfog/commentapi.aspx?PostID=150640</wfw:comment><comments>http://geeks.ms/blogs/rfog/archive/2009/06/17/v-237-deo-de-introducci-243-n-al-mfc-feature-pack-de-microsoft-en-microsoft.aspx#comments</comments><description>&lt;p&gt;Bueno, como pod&amp;eacute;is ver, aunque me queden un par de entradas sobre el Kindle, el RFOG sigue en la brecha de sus cosas de C++ y dem&amp;aacute;s zarandajas, que fue el origen de este Blog. El que haya escrito poco sobre mis temas &amp;uacute;ltimamente se debe a que he tenido mucho trabajo y he estado enormemente ocupado... &amp;iquest;Qu&amp;eacute;? &amp;iquest;No te lo crees? Pues yo tampoco, para serte sincero. &lt;/p&gt;
&lt;p&gt;Esto de las ganas de escribir en el blog va y viene, y unas veces hay m&amp;aacute;s y otras menos, y las m&amp;aacute;s una perrer&amp;iacute;a de tumbarme a leer &lt;em&gt;novelicas de ciencia ficci&amp;oacute;n&lt;/em&gt; que no os lo creer&amp;iacute;ais (o a lo mejor s&amp;iacute;, vaya ust&amp;eacute; a saber).&lt;/p&gt;
&lt;p&gt;Bueno, dej&amp;eacute;monos de rollos patateros y vayamos al asunto:&lt;/p&gt;
&lt;p&gt;Ayer Microsoft public&amp;oacute; en &lt;a href="http://channel9.msdn.com/spain/"&gt;Channel 9 Espa&amp;ntilde;a&lt;/a&gt; un video muy chulo que he hecho sobre el Feature Pack. Es una introduccion r&amp;aacute;pida por las caracter&amp;iacute;sticas del mismo, y la verdad es que me hubiera gustado profundizar m&amp;aacute;s. No prometo que lo haga, pero tampoco que no... ya que por fin hay algo en MFC moderno, &amp;uacute;ltil y funcional (y que encima no le he encontrado ning&amp;uacute;n bug, y eso que llevo ya dos aplicaciones hechas con &amp;eacute;l).&lt;/p&gt;
&lt;p&gt;Bueno, pues nada, aqu&amp;iacute; est&amp;aacute; el v&amp;iacute;deo. Que lo disfrut&amp;eacute;is.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://channel9.msdn.com/posts/Daniel+Garzon/C-MFC-Feature-Pack/"&gt;http://channel9.msdn.com/posts/Daniel+Garzon/C-MFC-Feature-Pack/&lt;/a&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=150640" 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/SP1/default.aspx">SP1</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/tips/default.aspx">tips</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/lenguajes/default.aspx">lenguajes</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/videos/default.aspx">videos</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/MFC/default.aspx">MFC</category></item><item><title>Cómo abrir máquinas virtuales vmWare en ventanas independientes</title><link>http://geeks.ms/blogs/rfog/archive/2009/02/25/c-243-mo-abrir-m-225-quinas-virtuales-vmware-en-ventanas-independientes.aspx</link><pubDate>Wed, 25 Feb 2009 15:00:00 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:143437</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=143437</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/rfog/commentapi.aspx?PostID=143437</wfw:comment><comments>http://geeks.ms/blogs/rfog/archive/2009/02/25/c-243-mo-abrir-m-225-quinas-virtuales-vmware-en-ventanas-independientes.aspx#comments</comments><description>&lt;p&gt;Esta es una tarea pendiente que llevaba bastante tiempo detr&amp;aacute;s de conseguir. Quiz&amp;aacute;s lo que cuente aqu&amp;iacute; sea evidente para todos menos para mi, pero por si acaso -y para que no se me olvide-, voy a dejar constancia de ello.&lt;/p&gt;
&lt;p&gt;&amp;iquest;Qu&amp;eacute; desarrollador moderno no tiene varias m&amp;aacute;quinas virtuales para hacer sus experimentos y pruebas? Yo al menos tengo una buena espuerta de ellas, y si bien antes usaba Virtual PC, que no es un mal producto ni de lejos, al carecer de soporte para USB termin&amp;oacute; haciendo que cada vez menos m&amp;aacute;quinas virtuales estuvieran en Virtual PC y m&amp;aacute;s en vmWare, y en la &amp;uacute;ltima instalaci&amp;oacute;n de Windows decid&amp;iacute; prescindir de Virtual PC ya que muchas veces lanzaba m&amp;aacute;quinas de ambos productos sin darme cuenta y terminaba con una bonita pantalla azul debida al bit de virtualizaci&amp;oacute;n...&lt;/p&gt;
&lt;p&gt;Virtual PC mantiene una lista de m&amp;aacute;quinas virtuales y cuando abres una la lanza en una ventana independiente. vmWare tiene similares opciones pero quedan encastradas en la misma ventana virtual, de modo que, aparte de estar siempre visibles, reducen la cantidad de m&amp;aacute;quina virtual que pueden mostrar. No obstante, todas esas cosas se pueden ocultar sin problema, pero entonces estamos un poco ciegos en cuanto qu&amp;eacute; tenemos abierto...&lt;/p&gt;
&lt;p&gt;Una soluci&amp;oacute;n es lanzar las m&amp;aacute;quinas virtuales y luego entrar en ellas mediante escritorio remoto... pero si est&amp;aacute;s haciendo por ejemplo una aplicaci&amp;oacute;n que usa gr&amp;aacute;ficos de forma intensiva el resultado no es muy bueno, no en relaci&amp;oacute;n a tener la pantalla directamente...&lt;/p&gt;
&lt;p&gt;As&amp;iacute; que yo empec&amp;eacute; por tener una carpeta en el escritorio conteniendo un acceso directo a cada una de&amp;nbsp;las m&amp;aacute;quinas virtuales que tengo, al abrir la primera todo va bien, pero al abrir la segunda &amp;eacute;sta oculta la anterior de modo que luego tienes que estar saltando entre una y otra desde el men&amp;uacute; &lt;em&gt;Window&lt;/em&gt;, o, lo que es peor, si est&amp;aacute;s en pantalla completa tienes que quitarla, cambiar y volver (evidentemente, quien tenga un solo monitor no est&amp;aacute; afectado por ese problema, pero quien use dos como yo, se pueden mostrar dos m&amp;aacute;quinas virtuales a pantalla completa en vmWare, una en cada monitor).&lt;/p&gt;
&lt;p&gt;Evidentemente, no hay ning&amp;uacute;n switch ni ninguna opci&amp;oacute;n para hacer esto. Es decir, no hay ning&amp;uacute;n sitio ni en las opciones del programa ni en las de la l&amp;iacute;nea de comandos que diga &amp;quot;abre cada m&amp;aacute;quina virtual en una ventana independiente&amp;quot;. La forma m&amp;aacute;s directa es ir al men&amp;uacute; inicio, abrir una nueva sesi&amp;oacute;n de vmWare, y desde el programa cargar la nueva m&amp;aacute;quina virtual (y eso si no est&amp;aacute; cargada ya en otra ventana) y lanzarla.&lt;/p&gt;
&lt;p&gt;Pues bien, la soluci&amp;oacute;n es tan evidente que... bueno, mejor la digo y no se hable m&amp;aacute;s:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;span style="text-decoration:underline;"&gt;Abrir cada m&amp;aacute;quina virtual wmWare en una ventana independiente&lt;/span&gt;&lt;/strong&gt; a&amp;nbsp;partir de un acceso directo.&lt;/p&gt;
&lt;p&gt;Bueno, lo primero es a&amp;ntilde;adir la ruta de vmWare a tu path. En mi caso es &amp;quot;C:\Program Files (x86)\VMware&amp;quot;. Luego, cambiar el acceso directo de, por ejemplo &amp;quot;C:\MisVM\VM tonta\VM tonta.vmx&amp;quot; a &amp;#39;vmware &amp;quot;C:\MisVM\VM tonta\VM tonta.vmx&amp;quot;&amp;#39;. As&amp;iacute; se abrir&amp;aacute; cada una en una ventana independiente.&lt;/p&gt;
&lt;p&gt;&lt;span style="text-decoration:line-through;"&gt;S&amp;iacute;, ya lo s&amp;eacute;, es una tonter&amp;iacute;a.&lt;/span&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=143437" 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/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></item><item><title>Hemos leído: John Lakos: Large-Scale C++ Software Design</title><link>http://geeks.ms/blogs/rfog/archive/2009/02/19/hemos-le-237-do-john-lakos-large-scale-c-software-design.aspx</link><pubDate>Thu, 19 Feb 2009 16:10:00 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:143062</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=143062</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/rfog/commentapi.aspx?PostID=143062</wfw:comment><comments>http://geeks.ms/blogs/rfog/archive/2009/02/19/hemos-le-237-do-john-lakos-large-scale-c-software-design.aspx#comments</comments><description>&lt;p align="justify"&gt;&lt;a target="_blank" href="http://www.amazon.com/Large-Scale-Software-Addison-Wesley-Professional-Computing/dp/0201633620"&gt;&lt;img border="0" align="left" width="192" src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rfog/clip_5F00_image002_5F00_71AE1690.jpg" hspace="12" alt="clip_image002" height="244" style="border-right:0px;border-top:0px;display:inline;margin-left:0px;border-left:0px;margin-right:0px;border-bottom:0px;" title="clip_image002" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p align="justify"&gt;Bueno, realmente no lo hemos le&amp;iacute;do &lt;i&gt;del todo&lt;/i&gt;, ya que nos quedan cien de las ochocientas p&amp;aacute;ginas que componen este mamotreto, pero que si no pasa nada caer&amp;aacute;n esta noche de forma r&amp;aacute;pida, ya que son varios ap&amp;eacute;ndices.&lt;/p&gt;
&lt;p align="justify"&gt;&amp;iquest;Por d&amp;oacute;nde empezar? Uf. Es un libro dif&amp;iacute;cil de leer, no por la prosa, sino por el contenido, altamente &amp;ndash;muy altamente- t&amp;eacute;cnico. El autor parte de que ya sabes C++, pero no el C++ que puedas aprender en la escuela, sino C++ &lt;i&gt;de verdad&lt;/i&gt;. No se entretiene en explicarte esto o aquello, sino que parte a saco, suponiendo que eres un programador profesional.&lt;/p&gt;
&lt;p align="justify"&gt;Como el t&amp;iacute;tulo indica, el libro est&amp;aacute; destinado a los desarrolladores de grandes proyectos en C++, aunque ciertamente si eres uno que trabaja en solitario o con poco acompa&amp;ntilde;amiento como yo el libro tambi&amp;eacute;n te va a servir, y no poco, aunque haya partes que en principio no est&amp;eacute;n dedicadas a ti, pero siempre se pueden sacar buenas ideas y conceptos.&lt;/p&gt;
&lt;p align="justify"&gt;John comienza con el hecho de que la mayor&amp;iacute;a de libros sobre dise&amp;ntilde;o de C++ se centran en la parte &lt;i&gt;l&amp;oacute;gica&lt;/i&gt; en lugar de la &lt;i&gt;f&amp;iacute;sica&lt;/i&gt;, es decir, mucha clase, mucho encapsulamiento, mucha jerarqu&amp;iacute;a de objetos, pero sin tener en cuenta el coste de compilaci&amp;oacute;n que supone usar tales abstracciones en un lenguaje como C++. Y nos da ejemplos pr&amp;aacute;cticos y nos muestra c&amp;oacute;mo un cambio trivial en una l&amp;iacute;nea de un fichero puede suponer la compilaci&amp;oacute;n completa de un sistema que puede tardar horas o incluso d&amp;iacute;as.&lt;/p&gt;
&lt;p align="justify"&gt;Despu&amp;eacute;s de estudiar m&amp;eacute;tricas sobre el tema, el nivel de acoplamiento entre componentes, etc., comienza lo bueno: t&amp;eacute;cnicas, sesudamente razonadas, para mejorar el dise&amp;ntilde;o, no l&amp;oacute;gico, sino f&amp;iacute;sico, de forma que los tiempos de compilaci&amp;oacute;n y la estabilidad de los interfaces p&amp;uacute;blicos mejoren en gran medida.&lt;/p&gt;
&lt;p align="justify"&gt;Algunos conceptos son triviales y reducen dr&amp;aacute;sticamente el tiempo de compilaci&amp;oacute;n, otros son m&amp;aacute;s complejos y requieren una refactorizaci&amp;oacute;n completa (o casi) del dise&amp;ntilde;o. Lo bueno del libro es que siempre, siempre, vamos guiados por razonamientos formales y por ejemplos completamente v&amp;aacute;lidos, de modo que la conclusi&amp;oacute;n es obvia: el autor tiene toda la raz&amp;oacute;n.&lt;/p&gt;
&lt;p align="justify"&gt;El n&amp;uacute;cleo del libro son los cap&amp;iacute;tulos 5, 6 y 7, en los que nos habla de los tres niveles a considerar: el de los componentes (entendidos como una unidad f&amp;iacute;sica), el de los paquetes y el de los grupos de paquetes. Ciertamente en los tres cap&amp;iacute;tulos se repiten casi las mismas las t&amp;eacute;cnicas aplicadas a cada nivel, pero vienen destinadas a diferentes roles dentro de un te&amp;oacute;rico grupo de desarrollo. De hecho, he estado pr&amp;aacute;cticamente como un mes y medio dedicado a leer, anotar y releer parte de estos cap&amp;iacute;tulos, aunque el 7 se me quede un poco grande.&lt;/p&gt;
&lt;p align="justify"&gt;La tercera parte del libro trata sobre conceptos l&amp;oacute;gicos, y es m&amp;aacute;s un compendio de reglas sueltas relativamente razonadas que un todo coherente. No obstante, resulta un buen complemento a lo anterior. Por ejemplo, nos explica la mejor forma de sobrecargar los operadores y por qu&amp;eacute; otras sobrecargas son generalmente incorrectas aunque formalmente v&amp;aacute;lidas, el uso de tipos y de par&amp;aacute;metros, por qu&amp;eacute; no sobrecargar el operador &lt;i&gt;new&lt;/i&gt; de forma global y un largo etc&amp;eacute;tera.&lt;/p&gt;
&lt;p align="justify"&gt;Se nota que el libro es algo viejo. Nos habla de los espacios de nombres como novedad, y de las plantillas como algo ineficaz y peligroso y que de momento los compiladores no saben tratar adecuadamente, pero sin embargo, nos da razonadas ideas sobre su uso.&lt;/p&gt;
&lt;p align="justify"&gt;Aunque no es un libro para tener sobre la mesa de trabajo, s&amp;iacute; que puede resultar &amp;uacute;til su lectura peri&amp;oacute;dica y su consulta cuando nuestro proyecto se vuelva un poco inmanejable. Adem&amp;aacute;s, al final de cada cap&amp;iacute;tulo y del propio libro, viene un interesante resumen de todos los temas tratados en cada uno de ellos.&lt;/p&gt;
&lt;p align="justify"&gt;En fin, que se trata de un libro muy recomendable para aquellos profesionales de C++ o amateurs que quieran serlo.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=143062" 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/rationale/default.aspx">rationale</category><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></item><item><title>La estructura intraducible, I (de Interop y otras yerbas)</title><link>http://geeks.ms/blogs/rfog/archive/2008/12/19/la-estructura-intraducible-i-de-interop-y-otras-yerbas.aspx</link><pubDate>Fri, 19 Dec 2008 19:23:45 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:132200</guid><dc:creator>Rafael Ontivero</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/rfog/rsscomments.aspx?PostID=132200</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/rfog/commentapi.aspx?PostID=132200</wfw:comment><comments>http://geeks.ms/blogs/rfog/archive/2008/12/19/la-estructura-intraducible-i-de-interop-y-otras-yerbas.aspx#comments</comments><description>&lt;p&gt;A veces resulta curioso cómo algo tan sencillo como mapear una estructura de C en .NET se puede convertir en un algo muy cercano a una pesadilla dependiendo del lenguaje que hayamos elegido para realizarlo. Partamos de la siguiente estructura de C:&lt;/p&gt;  &lt;pre&gt;typedef struct
{
    BYTE byOut[4]; // Outputs [0..3]
    BYTE byAux; // Aux output
} usbOutput;&lt;/pre&gt;

&lt;p&gt;A simple vista es algo muy elemental: un array de cuatro bytes y uno más después. Esto en una máquina Intel en realidad termina ocupando 8 bytes, 4 para el primer elemento y otros cuatro para el segundo si no se cambia la alineación.&lt;/p&gt;

&lt;p&gt;La traducción a C# requiere de ciertos trucos un tanto oscuros y no muy bien documentados:&lt;/p&gt;

&lt;pre&gt;[StructLayoutAttribute(LayoutKind.Sequential)]
public struct usbOutput
{
    [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 4)]
    public byte[] byOut;
    public byte byAux;
}&lt;/pre&gt;

&lt;p&gt;Todo el secreto está en la declaración de los atributos que preceden al array. Básicamente le estamos diciendo al runtime que lo que viene a continuación es un array embebido directamente y no un array normal; es decir, que en lugar de guardar un puntero en la estructura y coloque el array en otro lugar, lo que está haciendo es colocar el array de cuatro elementos directamente en la estructura.&lt;/p&gt;

&lt;p&gt;El autor no sabe si esa construcción funciona o no porque no lo ha probado, pero supone que debe hacerlo ya que si no difícilmente se iba a poder trabajar con Win32 desde C#.&lt;/p&gt;

&lt;p&gt;Pero resulta que uno está haciendo el ensamblado en C++/CLI para aprovechar las facilidades del código mixto, por lo que piensa que la traducción directa servirá:&lt;/p&gt;

&lt;pre&gt;[StructLayout(LayoutKind::Sequential)]
public value struct usbOutput
{
    [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 4)]
    Array&amp;lt;byte&amp;gt;^ byOut;
    byte byAux;
};&lt;/pre&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Pero tras las primeras pruebas descubre que no, que .NET te ignora olímpicamente y el array &lt;i&gt;byOut&lt;/i&gt; se queda como un puntero en la estructura, con el consiguiente desbarajuste cuando dicha estructura es bloqueada (mediante un &lt;i&gt;pin_ptr&lt;/i&gt;) y pasada a la función nativa. Con la experiencia del autor, en general o bien se te cuelga el IDE o bien el aplicativo empieza a hacer cosas bastante extrañas…&lt;/p&gt;

&lt;p&gt;Tras recorrerse Internet completo, de hecho el autor llegó hasta &lt;a href="http://www.shibumi.org/eoti.htm"&gt;aquí&lt;/a&gt;, no descubre nada que le sea útil excepto una construcción de Nishant Sivakumar que no le funciona bien. Pero como el autor de esta entrada tiene el libro de Nish, busca el original y descubre que la versión encontrada en Internet no funciona, pero la del libro sí lo hace, pero funciona sólo en C++/CLI, ya que si se llama a &lt;i&gt;byIn&lt;/i&gt; desde C#, el compilador falla debido a que la sobrecarga de operadores es mucho más versátil en C++ y C++/CLI que en C# y éste no sabe cómo actuar.&lt;/p&gt;

&lt;p&gt;La solución de Nish se puede encontrar en la página 185 de su libro titulado &lt;i&gt;&lt;a href="http://www.manning.com/sivakumar/"&gt;C++/CLI in Action&lt;/a&gt;&lt;/i&gt;, que recomiendo encarecidamente a todo aquel que quiera aprender este lenguaje. &lt;/p&gt;

&lt;p&gt;Mi solución parte de la de Nish con una ligera modificación, que es la de sustituir la sobrecarga del operador de acceso indexado, [], por el indexador por defecto.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;&lt;u&gt;La solución&lt;/u&gt;&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;La potencia expresiva de C++ es prácticamente infinita, ya que si existe alguna construcción en cualquier otro lenguaje que no exista en C++, resulta poco menos que seguro que se pueda simular y casi integrar en el lenguaje a través una biblioteca que simule el tipo o el constructo necesario, y eso es lo que aquí hemos hecho.&lt;/p&gt;

&lt;p&gt;Necesitamos &lt;i&gt;algo&lt;/i&gt; que nos permita insertar una secuencia repetida de un mismo elemento y que tenga semántica de array… Pues nada, elemental, querido Watson:&lt;/p&gt;

&lt;pre&gt;template&amp;lt;typename T,int size&amp;gt;
[StructLayout(LayoutKind::Sequential,Size=sizeof(T)*size)]
public value class FixedSizeArray
{
    T FixedElementField;
    public:
    property T default[int]
    {
        T get(int i)
        {
            return *(&amp;amp;FixedElementField+i);
        }
        void set(int i,T t)
        {
            *(&amp;amp;FixedElementField+i)=t;
        }
    }
};&lt;/pre&gt;

&lt;p&gt;Creamos un nuevo tipo que recibe un tipo llamado T y un entero que va a indicar el tamaño estático del array. Luego le decimos a .NET que nuestra clase es una estructura secuencial y que su tamaño es de tantas veces como elementos a repetir en relación al tipo base.&lt;/p&gt;

&lt;p&gt;Y declaramos el tipo en cuestión, que hemos llamado &lt;i&gt;FixedSizeArray&lt;/i&gt; y que contiene un elemento del tipo T. Asimismo posee un indexador por defecto que recibirá un entero que será el índice del elemento a leer o escribir. Lo único que le falta al ejemplo es controlar el tamaño del índice, pero como en el caso del autor es algo interno a él mismo, lo obvia.&lt;/p&gt;

&lt;p&gt;La línea más curiosa de todas es el acceso al elemento interno:&lt;/p&gt;

&lt;p&gt;*(&amp;amp;FixedElementField+i)&lt;/p&gt;

&lt;p&gt;Expresándolo paso a paso, en primer lugar obtenemos la dirección de memoria de &lt;i&gt;FixedElementField&lt;/i&gt; a través del operador &amp;amp;. A esa dirección añadimos el índice como si de un puntero de C++ se tratara, y luego desreferenciamos para obtener (o asignar) el valor.&lt;/p&gt;

&lt;p&gt;A primera vista no debería funcionar, pero sí que lo hace ya que debemos tener conocimiento de cómo C++ y C++/CLI (y en general casi cualquier lenguaje orientado a objetos funciona). Cuando uno crea un objeto de una clase, sólo está creando el bloque de datos del mismo, ya que la clase ha sido traducida a una lista de funciones más o menos globales que residen en el segmento de código, y cuando se invoca un método cualquiera, realmente estamos haciendo una llamada de función global pasando en primer lugar un puntero a la dirección donde están los datos…&lt;/p&gt;

&lt;p&gt;El uso de esta construcción es bien sencilla:&lt;/p&gt;

&lt;pre&gt;[StructLayout(LayoutKind::Sequential)]
public value struct usbOutput
{
    FixedSizeArray&amp;lt;byte,4&amp;gt;byOut;
    byte byAux;
};&lt;/pre&gt;

&lt;p&gt;Simplemente indicamos un objeto del tipo &lt;i&gt;FixedSizeArray&lt;/i&gt; del tipo y tamaños adecuado. Y el acceso desde, por ejemplo, C#, todavía lo es más:&lt;/p&gt;

&lt;pre&gt;usbInput input=new usbInput();
input. byOut[2]=55;
Console.WriteLine(input. byOut[2]);
GetInputs(ref input);
//etc.&lt;/pre&gt;

&lt;p&gt;La única limitación de esta construcción es que sólo permite simular arrays de una dimensión. En una próxima entrada pondré cómo hacerlo para elementos de varias.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=132200" width="1" height="1"&gt;</description><category domain="http://geeks.ms/blogs/rfog/archive/tags/c_2B002B002F00_cli/default.aspx">c++/cli</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/c_2B002B00_/default.aspx">c++</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/Visual+Studio/default.aspx">Visual Studio</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/interop/default.aspx">interop</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/tips/default.aspx">tips</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/Win32/default.aspx">Win32</category></item><item><title>C++: Insertar un ejecutable dentro de otro… y luego ejecutarlo</title><link>http://geeks.ms/blogs/rfog/archive/2008/09/11/c-insertar-un-ejecutable-dentro-de-otro-y-luego-ejecutarlo.aspx</link><pubDate>Thu, 11 Sep 2008 15:10:00 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:98382</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=98382</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/rfog/commentapi.aspx?PostID=98382</wfw:comment><comments>http://geeks.ms/blogs/rfog/archive/2008/09/11/c-insertar-un-ejecutable-dentro-de-otro-y-luego-ejecutarlo.aspx#comments</comments><description>&lt;p&gt;Vamos a explicar cómo tomar un ejecutable (o cualquier otro fichero binario), insertarlo dentro de un ejecutable y posteriormente cómo recuperar ese ejecutable embebido, soltarlo a disco y ejecutarlo. El escenario típico es borrar el propio ejecutable que actúa como hospedante, pero seguro que a las mentes calenturientas de mis lectores se les ocurren más aplicaciones. 
&lt;p&gt;El problema no existía en Windows 95 y siguientes: un programa podía borrar su propio ejecutable y terminar sin ningún problema (o casi). Pero en los núcleos NT hacer eso es harina de otro costal. Teóricamente se puede hacer mientras que el ejecutable a borrar no abra ningún &lt;i&gt;handle&lt;/i&gt;… pero evidentemente cualquier ejecutable suele abrir no uno, sino infinidad de ellos. 
&lt;p&gt;La solución consiste entonces en disponer de dos ejecutables en disco. El primero hará su tarea y llamará al segundo antes de terminar, que tras unos instantes procederá a borrar el primero, quedando éste último en disco. Pero entonces tenemos que distribuir dos ficheros y colocarlos en el mismo sitio, por lo que la mejor solución es que el primero contenga al segundo en sus entrañas y lo use a voluntad. Incidentalmente el segundo podría decir a Windows que lo borre en el siguiente reinicio, pero no vamos a entrar en detalles sobre esto. 
&lt;p&gt;&lt;b&gt;&lt;u&gt;Primer paso: Insertar el ejecutable&lt;/u&gt;&lt;/b&gt; 
&lt;p&gt;Suponiendo que tengamos ya construido nuestro ejecutable (que vamos a llamar “borra.exe”), insertar un recurso del tipo RCDATA en un fichero ejecutable es una tarea trivial. Basta con abrir el fichero de recursos del ejecutable (el .rc) como texto e insertar la línea:&lt;pre&gt;ELEXE RCDATA &amp;quot;..\\final\\Win32\\Release\\borra.exe&amp;quot;&lt;/pre&gt;
&lt;p&gt;Recompilamos y ya tenemos el ejecutable como recurso binario embebido en nuestro propio ejecutable. Evidentemente no estamos limitados a ningún tipo de archivo en concreto. Podríamos hacerlo incluso con recursos normales (mapas de bits, iconos, cadenas, etc.). La única diferencia es la forma de recuperar un recurso binario de uno almacenado como estándar. 
&lt;p&gt;&lt;b&gt;&lt;u&gt;Segundo paso: Sacar el ejecutable y ponerlo en disco&lt;/u&gt;&lt;/b&gt; 
&lt;p&gt;Cuando queramos volcar nuestro ejecutable a disco, debemos ejecutar algo parecido a lo siguiente: 
&lt;blockquote&gt;&lt;pre&gt;HRSRC res=FindResource(NULL,_T(&amp;quot;ELEXE&amp;quot;),RT_RCDATA);
if(res==NULL)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return GetLastError();

int size=SizeofResource(NULL,res);
HGLOBAL hRes=LoadResource(NULL,res);
unsigned char *pRes=(unsigned char *)LockResource(hRes);

HANDLE hFile=CreateFile(szT2Path,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,0,NULL);
if(hFile==INVALID_HANDLE_VALUE)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return GetLastError();&lt;br /&gt;
WriteFile(hFile,pRes,size,&amp;amp;bytesWritten,NULL);
CloseHandle(hFile);

ShellExecute(HWND_DESKTOP,NULL,szT2Path,NULL,NULL,SW_SHOWNORMAL);
&lt;/pre&gt;&lt;/blockquote&gt;
&lt;p&gt;El primer paso consiste en llamar a &lt;i&gt;FindResource&lt;/i&gt; con el nombre y el tipo de recurso. Si nuestro fichero hubiera estado almacenado en otro lugar que no fuera nuestro propio ejecutable, el primer parámetro a pasar es la instancia del fichero externo. 
&lt;p&gt;Tras tener un &lt;i&gt;handle&lt;/i&gt; válido, tenemos que mirar el tamaño que ocupa el recurso almacenado, lo que hacemos con &lt;i&gt;SizeofResource&lt;/i&gt;. 
&lt;p&gt;Ahora viene cargar el recurso en memoria y obtener un &lt;i&gt;handle&lt;/i&gt; de memoria (&lt;i&gt;LoadResource&lt;/i&gt;). Pero todavía no podemos acceder a los bytes de nuestro fichero, debemos bloquear el acceso a los mismos mediante &lt;i&gt;LockResource&lt;/i&gt;, lo que nos devolverá un área de memoria accesible. 
&lt;p&gt;Aquí el autor lo ha asignado a un buffer de caracteres sin signo, pero realmente cualquier tipo de dato es perfectamente válido, aunque tenemos que tener en cuenta de no guardar ningún byte de más en el fichero final. Haciéndolo con un buffer de caracteres nos aseguramos de guardar el tamaño correcto. 
&lt;p&gt;Ya solo nos queda guardar el buffer a disco y hacer la llamada para ejecutar el fichero extraído. 
&lt;p&gt;Quizás nos preguntemos por qué no hemos liberado la memoria apuntada por pRes: está expresamente descrito en la documentación de la MSDN: no debemos hacerlo nosotros, ya lo hará el sistema cuando corresponda. 
&lt;p&gt;&lt;b&gt;&lt;u&gt;Consideraciones finales&lt;/u&gt;&lt;/b&gt; 
&lt;p&gt;Evidentemente una solución más sencilla sería marcar el propio ejecutable para ser borrado en el siguiente reinicio en lugar de hacer toda esta parafernalia, pero a veces puede no interesarnos que dicho fichero esté en disco hasta ese momento. 
&lt;p&gt;De todos modos aplicaciones para esto las hay a montones. Soltar un ejecutable que haga algo, termine y luego sea borrado por el programa principal, forzar un reinicio del programa principal, distribuir un solo exe que luego suelte todos los ficheros que necesite…&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=98382" 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/tips/default.aspx">tips</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/Win32/default.aspx">Win32</category></item><item><title>Singleton con y sin Singleton</title><link>http://geeks.ms/blogs/rfog/archive/2008/03/03/singleton-con-y-sin-singleton.aspx</link><pubDate>Mon, 03 Mar 2008 18:20:28 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:76303</guid><dc:creator>Rafael Ontivero</dc:creator><slash:comments>21</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/rfog/rsscomments.aspx?PostID=76303</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/rfog/commentapi.aspx?PostID=76303</wfw:comment><comments>http://geeks.ms/blogs/rfog/archive/2008/03/03/singleton-con-y-sin-singleton.aspx#comments</comments><description>&lt;p&gt;Ahora que est&amp;#225;n de moda los antipatrones, voy a explicar un patr&amp;#243;n que es muy famoso pero que no me gusta absolutamente nada, no por el dise&amp;#241;o del mismo, sino por los efectos laterales no deseados que genera. Por ello tambi&amp;#233;n voy a explicar otra forma de construirlo que me gusta m&amp;#225;s, aunque adolece de otras limitaciones.&lt;/p&gt;  &lt;p&gt;Singleton es un patr&amp;#243;n que nos obliga a tener una sola instancia de una clase, es decir, globalmente s&amp;#243;lo podremos disponer de un objeto de ese tipo. El truco est&amp;#225; en conseguir que, hagamos lo que hagamos, no podamos crear m&amp;#225;s de una instancia.&lt;/p&gt;  &lt;p&gt;En lenguajes como C++ este patr&amp;#243;n tiene menos utilidad que en C++/CLI, C# o VB.NET, ya que la forma cl&amp;#225;sica de hacer algo similar es tener una variable global accesible por todos los m&amp;#243;dulos, cosa de la que suele encargarse el enlazador de hacer. &lt;/p&gt;  &lt;p&gt;Pero los lenguajes .NET adolecen de falta de variables globales; es decir, no puedes tener un objeto global y visible en toda la aplicaci&amp;#243;n. Personalmente no entiendo este purismo tan quisquilloso, ya que los lenguajes .NET no son precisamente orientados a objetos puros, y menos a&amp;#250;n con la especificaci&amp;#243;n 3.0 de C#. Y si encima este hecho complica bastante ciertos desarrollos, el absurdo sube de nivel.&lt;/p&gt;  &lt;p&gt;Pero es lo que hay.&lt;/p&gt;  &lt;p&gt;La soluci&amp;#243;n para tener un objeto global es disponer de una clase est&amp;#225;tica. Si bien a priori resulta una buena idea, en la pr&amp;#225;ctica no lo es tanto. Independientemente del hecho de que los constructores est&amp;#225;ticos en .NET no funcionan muy bien o, en otras palabras, tienen bastante bugs (al menos en la versi&amp;#243;n 2.0, aunque dudo mucho que lo hayan solucionado en los SP1), tenemos ciertas limitaciones, como la imposibilidad de que se llame a otro constructor est&amp;#225;tico de forma encadenada&amp;#8230;&lt;/p&gt;  &lt;p&gt;&amp;#191;Y por qu&amp;#233; comento esto? Pues porque el patr&amp;#243;n Singleton utiliza una variable y un constructor est&amp;#225;tico. Ve&amp;#225;moslo en C#:&lt;/p&gt;  &lt;div&gt;   &lt;div style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:#f4f4f4;border-bottom-style:none;"&gt;     &lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:white;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;   1:&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;using&lt;/span&gt; System;&lt;/pre&gt;

    &lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:#f4f4f4;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;   2:&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;using&lt;/span&gt; System.Collections.Generic;&lt;/pre&gt;

    &lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:white;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;   3:&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;using&lt;/span&gt; System.Text;&lt;/pre&gt;

    &lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:#f4f4f4;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;   4:&lt;/span&gt;&amp;#160; &lt;/pre&gt;

    &lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:white;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;   5:&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;class&lt;/span&gt; Singleton&lt;/pre&gt;

    &lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:#f4f4f4;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;   6:&lt;/span&gt; {&lt;/pre&gt;

    &lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:white;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;   7:&lt;/span&gt;     &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;static&lt;/span&gt; Singleton Instancia=&lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Singleton();&lt;/pre&gt;

    &lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:#f4f4f4;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;   8:&lt;/span&gt;&amp;#160; &lt;/pre&gt;

    &lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:white;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;   9:&lt;/span&gt;     &lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; Singleton() {}&lt;/pre&gt;

    &lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:#f4f4f4;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;  10:&lt;/span&gt;&amp;#160; &lt;/pre&gt;

    &lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:white;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;  11:&lt;/span&gt;     &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; Numero;&lt;/pre&gt;

    &lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:#f4f4f4;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;  12:&lt;/span&gt;     &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; DiNumero()&lt;/pre&gt;

    &lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:white;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;  13:&lt;/span&gt;     {&lt;/pre&gt;

    &lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:#f4f4f4;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;  14:&lt;/span&gt;         Console.WriteLine(Numero++.ToString());&lt;/pre&gt;

    &lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:white;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;  15:&lt;/span&gt;     }&lt;/pre&gt;

    &lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:#f4f4f4;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;  16:&lt;/span&gt; }&lt;/pre&gt;

    &lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:white;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;  17:&lt;/span&gt;&amp;#160; &lt;/pre&gt;

    &lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:#f4f4f4;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;  18:&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;class&lt;/span&gt; Program&lt;/pre&gt;

    &lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:white;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;  19:&lt;/span&gt; {&lt;/pre&gt;

    &lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:#f4f4f4;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;  20:&lt;/span&gt;     &lt;span style="color:#0000ff;"&gt;static&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; Main(&lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;[] args)&lt;/pre&gt;

    &lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:white;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;  21:&lt;/span&gt;     {&lt;/pre&gt;

    &lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:#f4f4f4;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;  22:&lt;/span&gt;         Singleton.Instancia.Numero = 33;&lt;/pre&gt;

    &lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:white;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;  23:&lt;/span&gt;         &lt;span style="color:#0000ff;"&gt;for&lt;/span&gt; (&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; i = 0; i &amp;lt; 10;i++)&lt;/pre&gt;

    &lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:#f4f4f4;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;  24:&lt;/span&gt;             Singleton.Instancia.DiNumero();&lt;/pre&gt;

    &lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:white;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;  25:&lt;/span&gt;     }&lt;/pre&gt;

    &lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:#f4f4f4;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;  26:&lt;/span&gt; }&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Observamos que el truco est&amp;#225; en definir un constructor privado. Al hacerlo, ya no podremos equivocarnos y crear varias instancias de esta clase, y la &amp;#250;nica forma de acceder al &amp;#250;nico objeto que pueda haber en toda la aplicaci&amp;#243;n es mediante&lt;/p&gt;

&lt;div&gt;
  &lt;div style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:#f4f4f4;border-bottom-style:none;"&gt;
    &lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:white;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;   1:&lt;/span&gt; Singleton.Instancia&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Si intentamos crearnos un objeto del tipo Singleton, el compilador protestar&amp;#225; y nos dir&amp;#225; que el constructor no est&amp;#225; accesible.&lt;/p&gt;

&lt;p&gt;Si alguien quiere una explicaci&amp;#243;n m&amp;#225;s en detalle, se puede pasar por la &lt;a href="http://msdn2.microsoft.com/en-us/library/ms998558.aspx"&gt;MSDN&lt;/a&gt; o por &lt;a href="http://www.eslomas.com/index.php/archives/2005/08/09/patron-singleton-con-c-sharp/"&gt;aqu&amp;#237;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&amp;#191;Nadie ve el problema? &lt;/p&gt;

&lt;p&gt;Pues hay dos. El primero ya lo hemos dicho: tenemos un objeto global al sistema, que es est&amp;#225;tico y por tanto sigue unas reglas algo diferentes, como la imposibilidad de hacer una llamada a otra variable est&amp;#225;tica que implemente su propio constructor est&amp;#225;tico dentro del constructor de nuestro Singleton&amp;#8230; O en otras palabras: no podemos tener Singletones anidados, no al menos bajo .NET.&lt;/p&gt;

&lt;p&gt;Pero el mayor problema es otro. Cuando se habla de Singleton, se pone un ejemplo con dos l&amp;#237;neas de c&amp;#243;digo y listo. Pero una clase de la Vida Real&amp;#8482; no es sencilla. Tendremos varios m&amp;#233;todos miembro, as&amp;#237; como variables. &amp;#191;C&amp;#243;mo las inicializamos? &amp;#191;En el constructor? &amp;#161;Pero si no tiene constructor al que podamos pasarle valores! &amp;#191;Las ponemos p&amp;#250;blicas? &amp;#191;Propiedades?&lt;/p&gt;

&lt;p&gt;Una soluci&amp;#243;n es la mostrada aqu&amp;#237;:&lt;/p&gt;

&lt;div&gt;
  &lt;div style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:#f4f4f4;border-bottom-style:none;"&gt;
    &lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:white;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;   1:&lt;/span&gt; Singleton.Instancia.Numero = 33;&lt;/pre&gt;

    &lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:#f4f4f4;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;   2:&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;for&lt;/span&gt; (&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; i = 0; i &amp;lt; 10;i++)&lt;/pre&gt;

    &lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:white;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;   3:&lt;/span&gt;     Singleton.Instancia.DiNumero();&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Pero a m&amp;#237; al menos eso me parece una guarrer&amp;#237;a mayor, y m&amp;#225;s cuando haya varios datos miembro, como suele ser habitual en clases no triviales&amp;#8230; La &amp;#250;nica cosa que podemos hacer es especificar valores por defecto en el constructor est&amp;#225;tico:&lt;/p&gt;

&lt;div&gt;
  &lt;div style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:#f4f4f4;border-bottom-style:none;"&gt;
    &lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:white;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;   1:&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; Singleton() { Numero = 50; }&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Pero eso s&amp;#243;lo alivia el problema, no lo soluciona.&lt;/p&gt;

&lt;p&gt;Qu&amp;#233; bonito ser&amp;#237;a que pudi&amp;#233;ramos indicar algo como&lt;/p&gt;

&lt;div&gt;
  &lt;div style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:#f4f4f4;border-bottom-style:none;"&gt;
    &lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:white;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;   1:&lt;/span&gt; [Pattern(Singleton)]&lt;/pre&gt;

    &lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:#f4f4f4;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;   2:&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;class&lt;/span&gt; Singleton&lt;/pre&gt;

    &lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:white;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;   3:&lt;/span&gt; {&amp;#8230;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Y disponer de la clase como si tal cosa&amp;#8230; Pero esa es otra guerra.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;&lt;u&gt;Otra aproximaci&amp;#243;n&lt;/u&gt;&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Veamos ahora una variante, que es la que yo implemento en mis propios programas. Primero el c&amp;#243;digo:&lt;/p&gt;

&lt;div&gt;
  &lt;div style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:#f4f4f4;border-bottom-style:none;"&gt;
    &lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:white;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;   1:&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;using&lt;/span&gt; System;&lt;/pre&gt;

    &lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:#f4f4f4;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;   2:&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;using&lt;/span&gt; System.Collections.Generic;&lt;/pre&gt;

    &lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:white;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;   3:&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;using&lt;/span&gt; System.Text;&lt;/pre&gt;

    &lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:#f4f4f4;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;   4:&lt;/span&gt;&amp;#160; &lt;/pre&gt;

    &lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:white;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;   5:&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;class&lt;/span&gt; MiSingleton&lt;/pre&gt;

    &lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:#f4f4f4;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;   6:&lt;/span&gt; {&lt;/pre&gt;

    &lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:white;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;   7:&lt;/span&gt;     &lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;static&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; m_cuenta=0;&lt;/pre&gt;

    &lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:#f4f4f4;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;   8:&lt;/span&gt;&amp;#160; &lt;/pre&gt;

    &lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:white;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;   9:&lt;/span&gt;     &lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; m_numero;&lt;/pre&gt;

    &lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:#f4f4f4;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;  10:&lt;/span&gt;     &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; MiSingleton(&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; num)&lt;/pre&gt;

    &lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:white;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;  11:&lt;/span&gt;     {&lt;/pre&gt;

    &lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:#f4f4f4;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;  12:&lt;/span&gt;         m_cuenta++;&lt;/pre&gt;

    &lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:white;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;  13:&lt;/span&gt;         &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (m_cuenta &amp;gt; 1)&lt;/pre&gt;

    &lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:#f4f4f4;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;  14:&lt;/span&gt;             &lt;span style="color:#0000ff;"&gt;throw&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Exception(&lt;span style="color:#006080;"&gt;&amp;quot;RFOG Singleton Exception&amp;quot;&lt;/span&gt;);&lt;/pre&gt;

    &lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:white;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;  15:&lt;/span&gt;&amp;#160; &lt;/pre&gt;

    &lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:#f4f4f4;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;  16:&lt;/span&gt;         m_numero = num; &lt;/pre&gt;

    &lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:white;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;  17:&lt;/span&gt;     }&lt;/pre&gt;

    &lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:#f4f4f4;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;  18:&lt;/span&gt;     &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; DiNumero()&lt;/pre&gt;

    &lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:white;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;  19:&lt;/span&gt;     {&lt;/pre&gt;

    &lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:#f4f4f4;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;  20:&lt;/span&gt;         Console.WriteLine(m_numero++.ToString());&lt;/pre&gt;

    &lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:white;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;  21:&lt;/span&gt;     }&lt;/pre&gt;

    &lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:#f4f4f4;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;  22:&lt;/span&gt; }&lt;/pre&gt;

    &lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:white;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;  23:&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;class&lt;/span&gt; Program&lt;/pre&gt;

    &lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:#f4f4f4;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;  24:&lt;/span&gt; {&lt;/pre&gt;

    &lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:white;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;  25:&lt;/span&gt;     &lt;span style="color:#0000ff;"&gt;static&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; Main(&lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;[] args)&lt;/pre&gt;

    &lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:#f4f4f4;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;  26:&lt;/span&gt;     {&lt;/pre&gt;

    &lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:white;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;  27:&lt;/span&gt;         MiSingleton m = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; MiSingleton(33);&lt;/pre&gt;

    &lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:#f4f4f4;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;  28:&lt;/span&gt;         &lt;span style="color:#0000ff;"&gt;for&lt;/span&gt; (&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; i = 0; i &amp;lt; 10;i++)&lt;/pre&gt;

    &lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:white;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;  29:&lt;/span&gt;             m.DiNumero();&lt;/pre&gt;

    &lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:#f4f4f4;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;  30:&lt;/span&gt;&amp;#160; &lt;/pre&gt;

    &lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:white;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;  31:&lt;/span&gt;         MiSingleton n=&lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; MiSingleton(88);&lt;/pre&gt;

    &lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:#f4f4f4;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;  32:&lt;/span&gt;     }&lt;/pre&gt;

    &lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:white;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;  33:&lt;/span&gt; }&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Aqu&amp;#237; encontramos otros problemas y otras limitaciones, pero personalmente me gusta m&amp;#225;s as&amp;#237;. Definimos una variable est&amp;#225;tica, un entero que nos servir&amp;#225; para contar cu&amp;#225;ntas instancias de esta clase tenemos.&lt;/p&gt;

&lt;p&gt;Definimos un constructor p&amp;#250;blico al que podremos pasarle cualquier n&amp;#250;mero de par&amp;#225;metros que queramos, de hecho se trata de una clase normal y corriente que tiene un bloque de c&amp;#243;digo concreto en el constructor:&lt;/p&gt;

&lt;div&gt;
  &lt;div style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:#f4f4f4;border-bottom-style:none;"&gt;
    &lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:white;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;   1:&lt;/span&gt; m_cuenta++;&lt;/pre&gt;

    &lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:#f4f4f4;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;   2:&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (m_cuenta &amp;gt; 1)&lt;/pre&gt;

    &lt;pre style="padding-right:0px;padding-left:0px;font-size:8pt;padding-bottom:0px;margin:0em;overflow:visible;width:100%;color:black;border-top-style:none;line-height:12pt;padding-top:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-right-style:none;border-left-style:none;background-color:white;border-bottom-style:none;"&gt;&lt;span style="color:#606060;"&gt;   3:&lt;/span&gt;     &lt;span style="color:#0000ff;"&gt;throw&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Exception(&lt;span style="color:#006080;"&gt;&amp;quot;RFOG Singleton Exception&amp;quot;&lt;/span&gt;);&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;La segunda vez que intentemos instanciar esta clase obtendremos una excepci&amp;#243;n. Aqu&amp;#237; la limitaci&amp;#243;n est&amp;#225; en que nos daremos cuenta de nuestro error en tiempo de ejecuci&amp;#243;n, no de compilaci&amp;#243;n, lo que ciertamente es una desventaja seria pero que pierde fuerza cuando nos enfrentamos a las limitaciones y bugs de los constructores est&amp;#225;ticos. &lt;/p&gt;

&lt;p&gt;La segunda instanciaci&amp;#243;n dentro del bloque de &lt;i&gt;main()&lt;/i&gt; lanzar&amp;#225; la excepci&amp;#243;n. La otra limitaci&amp;#243;n a esto viene de la imposibilidad de tener variables globales y de que tengamos que pasar &lt;i&gt;m&lt;/i&gt; siempre que queramos usarlo.&lt;/p&gt;

&lt;p&gt;Lo ideal ser&amp;#237;a tener ambas opciones juntas, pero ciertamente dentro de .NET es imposible.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=76303" 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/bugs/default.aspx">bugs</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/tips/default.aspx">tips</category></item><item><title>La que os espera... (ji ji)</title><link>http://geeks.ms/blogs/rfog/archive/2008/02/01/la-que-os-espera-ji-ji.aspx</link><pubDate>Fri, 01 Feb 2008 10:37:00 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:68270</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=68270</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/rfog/commentapi.aspx?PostID=68270</wfw:comment><comments>http://geeks.ms/blogs/rfog/archive/2008/02/01/la-que-os-espera-ji-ji.aspx#comments</comments><description>&lt;p&gt;Hará como una hora que he recibido de Amazon mis últimas adquisiciones, que son los seis libros situados en la parte inferior que se pueden contemplar en la foto que acompaña esta entrada... casi 200 euros en libros, sumados a otros doscientos y pico de varios pedidos anteriores...&lt;/p&gt;
&lt;p&gt;A los de la foto hay que añadir el &amp;quot;Reverse Engineering&amp;quot; sobre el que he comentado y otro sobre patrones, en los que creo poco, por lo menos tal y como se presentan habitualmente (quizás se deba a que en las aplicaciones que yo desarrollo no hay sitio para ellos, y me refiero a sitio físico, ya que a veces con límites de 8 K para el código pocas florituras puedes hacer)...&lt;/p&gt;
&lt;p&gt;También hay que añadir un par de libros sobre C++/CLI que ya he comentado por estos lares y dos más sobre C# de los que hablé tiempo ha...&lt;/p&gt;
&lt;p&gt;Esto es como un vicio, una vez que compras en Amazon y te sale bien, ya no te puedes contener, tal ha sido el cambio de costumbres que mi librero habitual me dice que ya no me paso por la sección de informática... Y se lo he contado... Y me ha preguntado qué libros son los buenos... Lo mismo en unos meses veo libros en inglés en su escaparate, je je.&lt;/p&gt;
&lt;p&gt;Quiero aprovechar para contar un problema que tuve en Amazon y su satisfactoria solución. El pedido anterior a éste traía &amp;quot;Win32 Programming&amp;quot; (el que está arriba a la izquierda del todo), que son dos tomos, pero me vino uno solo... Puesto en contacto con Amazon, me pidieron que retornara el defectuoso y que les dijera cuánto me había costado. Así lo hice, y antes siquiera de terminar de leer el correo, ellos ya me habían enviado, cargándomelo, un nuevo paquete. Una vez que les informé del envío, de su tracking y de lo que me costó hacerlo, me ingresaron ese coste más el que me habían cargado por el nuevo envío... Y cuando recibieron el paquete me enviaron un correo con que todo había sido solucionado.&lt;/p&gt;
&lt;p&gt;Efectivamente, haciendo cuentas al final no tuve que pagar ningún dinero por &lt;strong&gt;SU&lt;/strong&gt; problema, si bien es cierto que son un tanto barrocos a la hora de procesar las órdenes.&lt;/p&gt;
&lt;p&gt;¿Qué? Ah, sí, el título de la entrada... Pues eso, que ya sabéis lo que voy a leer y estudiar... Así que andad preparados.&lt;/p&gt;
&lt;p&gt;Se me olvidaba, la foto:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/blogs/rfog/WindowsLiveWriter/Laqueosespera.jiji_A35E/013.jpg"&gt;&lt;img style="BORDER-RIGHT:0px;BORDER-TOP:0px;BORDER-LEFT:0px;BORDER-BOTTOM:0px;" height="244" alt="013" src="http://geeks.ms/blogs/rfog/WindowsLiveWriter/Laqueosespera.jiji_A35E/013_thumb.jpg" width="222" border="0" /&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=68270" 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/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/Sistemas+Operativos/default.aspx">Sistemas Operativos</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/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/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/lenguajes/default.aspx">lenguajes</category></item><item><title>C++/CLI y C# VII: GetLastError en escenarios de interop</title><link>http://geeks.ms/blogs/rfog/archive/2007/11/25/c-cli-y-c-vii-getlasterror-en-escenarios-de-interop.aspx</link><pubDate>Sun, 25 Nov 2007 19:59:00 GMT</pubDate><guid isPermaLink="false">2a2e7ade-7474-448b-9de5-1515d8bb7d1b:52607</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=52607</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://geeks.ms/blogs/rfog/commentapi.aspx?PostID=52607</wfw:comment><comments>http://geeks.ms/blogs/rfog/archive/2007/11/25/c-cli-y-c-vii-getlasterror-en-escenarios-de-interop.aspx#comments</comments><description>&lt;p&gt;&lt;b&gt;&lt;u&gt;Introducción&lt;/u&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Hay un tema que ha aparecido indirectamente en algunos mensajes del grupo de C# relativo al tema de Interop mediante atributos (que es el único que puede hacer C# y VB.NET), y que desde que estoy leyendo dicho grupo nadie ha advertido o ha tenido algún problema con él, o al menos yo no me he dado cuenta de ello.&lt;/p&gt;
&lt;p&gt;Cuando uno hace una llamada al API de Win32, muchas funciones devuelven un estado de error a través de un &lt;i&gt;handle&lt;/i&gt; inválido o simplemente devolviendo &lt;i&gt;FALSE&lt;/i&gt;. Es una consecuencia de los tiempos en que ni el compilador ni Windows soportaban ningún modelo de excepción. Era tarea del programador comprobar dicho valor de retorno y luego realizar una llamada a &lt;i&gt;&lt;a href="http://msdn2.microsoft.com/en-us/library/ms679360.aspx"&gt;GetLastError(),&lt;/a&gt;&lt;/i&gt; que devolvía un número y que se podía convertir a una cadena más o menos inteligible mediante una nueva llamada a otra función: &lt;i&gt;&lt;a href="http://msdn2.microsoft.com/en-us/library/ms679351.aspx"&gt;FormatMessage&lt;/a&gt;&lt;/i&gt;.&lt;/p&gt;
&lt;p&gt;Si ahora volvemos al entorno manejado, cuando queramos realizar una llamada a través de interop a cualquier función de Win32 que utiliza ese formato para retornar un error, nos encontramos con la duda de qué ocurre entre las dos llamadas, es decir, nuestra llamada al método y una segunda para obtener el error.&lt;/p&gt;
&lt;p&gt;El Interop por atributos funciona de la siguiente forma: cuando nosotros hacemos una llamada a través de este sistema, el compilador inserta una cosa llamada &lt;i&gt;thunk&lt;/i&gt;, que consiste en una llamada a ejecutar cierto código especial. Entre muchas otras cosas, este código se encarga de traer la DLL de Win32 a nuestro espacio de direcciones (es un decir, porque realmente no trae nada, sino que prepara el contexto para realizar la llamada), realizar la conversión de los parámetros en parámetros compatibles para Win32, ejecutar dicha función y volver a convertir todo el tema en valores que el .NET sea capaz de entender. Lento, muy lento.&lt;/p&gt;
&lt;p&gt;Cuando volvamos a llamar a otra función, la operación se repite, por lo que una vez que se ha realizado la llamada a la función que queríamos, cuando hagamos la nueva llamada a &lt;i&gt;GetLastError()&lt;/i&gt; repetiremos todo lo de arriba, de forma que hemos perdido el valor, ya que estamos en un nuevo contexto que nada tiene que ver con el anterior.&lt;/p&gt;
&lt;p&gt;Si seguimos las reglas tal y como las hemos planteado, el tema tendría un fallo garrafal en cuanto a funcionalidad hacia el API Win32… Pero lo cierto es que los chicos de MS no son tontos, y han solucionado el problema de forma bastante elegante, aunque ineficaz desde un punto de vista del rendimiento, pero creo que excepto permitiendo el Interop al estilo en que se permite en C++/CLI, es la única forma posible de hacerlo.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;&lt;u&gt;Cómo funciona por defecto&lt;/u&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Cuando hacemos una llamada al API Win32, el sistema de Interop hace por nosotros la llamada a &lt;i&gt;GetLastError()&lt;/i&gt; en cada llamada, de forma que dicho resultado se guarda en el contexto.&lt;/b&gt; Y podemos accederlo mediante el método &lt;i&gt;&lt;a href="http://msdn2.microsoft.com/es-es/library/system.runtime.interopservices.marshal.getlastwin32error(VS.80).aspx"&gt;Marshal.GetLastWin32Error().&lt;/a&gt;&lt;/i&gt;&lt;/p&gt;
&lt;p&gt;Es decir, cada vez que hagamos una llamada mediante Interop a una función del API de Win32, tendremos disponible el valor devuelto por el &lt;i&gt;GetLastError()&lt;/i&gt; de Win32, ya que dicha llamada se ha hecho automáticamente.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;&lt;u&gt;Activarlo y desactivarlo&lt;/u&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Este funcionamiento viene activado por defecto, y lo cierto es que añade más sobrecarga a un sistema ya sobrecargado de por sí ya que, ante cada llamada a una función de Windows, el sistema hace dos, además de guardar un valor en el TLS (Thread Local Storage) del contexto de ejecución en el que se haya realizado. Y nosotros tendremos que realizar también una nueva consulta a &lt;i&gt;Marshal.GetLastWin32Error()&lt;/i&gt;, y si queremos enseñar un mensaje bonito, a &lt;i&gt;FormatMessage()&lt;/i&gt; de nuevo, que no es una función sencilla de utilizar y que requiere también un buen trabajo de atributos y de interop.&lt;/p&gt;
&lt;p&gt;Una llamada a un método de USER32.DLL podría tener esta firma:&lt;/p&gt;
&lt;p&gt;[System.Runtime.InteropServices.DllImport(&amp;quot;user32.dll&amp;quot;)] &lt;br /&gt;extern static void SampleMethod();&lt;/p&gt;
&lt;p&gt;De esta forma, estamos indicando el funcionamiento por defecto, es decir, poder obtener el valor del error de Win32.&lt;/p&gt;
&lt;p&gt;Pero si especificamos esta forma:&lt;/p&gt;
&lt;p&gt;[System.Runtime.InteropServices.DllImport(&amp;quot;user32.dll&amp;quot;)], SetLastError=false] &lt;br /&gt;extern static void SampleMethod();&lt;/p&gt;
&lt;p&gt;Estamos indicando al sistema de Interop que no realice la llamada a &lt;i&gt;GetLastError()&lt;/i&gt;, de forma que optimizamos en cierta medida los accesos a Win32 siempre y cuando no nos interese determinar si hubo error o no.&lt;/p&gt;
&lt;p&gt;Un ejemplo podría ser una llamada a &lt;i&gt;MessageBeep()&lt;/i&gt;. Si falla poco podemos hacer, ya que el usuario no oirá nada y punto.&lt;/p&gt;
&lt;p&gt;Como siempre, la versión en PDF está &lt;a href="http://rfog.cmact.com/CppCLI/0007.pdf"&gt;aquí&lt;/a&gt;.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=52607" 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_2300_/default.aspx">C#</category><category domain="http://geeks.ms/blogs/rfog/archive/tags/tips/default.aspx">tips</category></item></channel></rss>