<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://geeks.ms/utility/FeedStylesheets/atom.xsl" media="screen"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang=""><title type="html">.NET o no .NET, esa es la cuestión</title><subtitle type="html">Artículos, comentarios, noticias e ideas sobre la programción .NET y nativa, generalmente sobre C++ y C++/CLI, aunque siempre habrá un poco de todo.</subtitle><id>http://geeks.ms/blogs/rfog/atom.aspx</id><link rel="alternate" type="text/html" href="http://geeks.ms/blogs/rfog/default.aspx" /><link rel="self" type="application/atom+xml" href="http://geeks.ms/blogs/rfog/atom.aspx" /><generator uri="http://communityserver.org" version="4.1.31106.3070">Community Server</generator><updated>2009-11-15T12:38:00Z</updated><entry><title>¿Por qué uso C++? (II)</title><link rel="alternate" type="text/html" href="/blogs/rfog/archive/2010/03/17/191-por-qu-233-uso-c-ii.aspx" /><id>/blogs/rfog/archive/2010/03/17/191-por-qu-233-uso-c-ii.aspx</id><published>2010-03-17T14:03:00Z</published><updated>2010-03-17T14:03:00Z</updated><content type="html">&lt;p align="justify"&gt;Esta entrada es la continuacón directa de &lt;a href="http://geeks.ms/blogs/rfog/archive/2010/03/10/191-por-qu-233-uso-c-i.aspx"&gt;esta otra&lt;/a&gt;.&lt;/p&gt;  &lt;p align="justify"&gt;Ya lo he dicho antes, hay aplicaciones que resultan absurdas realizadas en C++, y también otras que también lo son cuando están hechas con otros lenguajes. Imaginaros un Autocad o un Office que estuviera íntegramente escrito en .NET. Si ya nos quejamos del rendimiento y la velocidad de carga de ellos, ya no os digo si en lugar de ser código nativo fuera .NET, o peor aún, Java (No le deseo ningún mal a Java, pero es lento de cojones, y las aplicaciones que he visto hechas con él también lo son. Ignoro si se debe al propio lenguaje o a la posible incompetencia de los programadores, pero el hecho final es que es lento).&lt;/p&gt;  &lt;p align="justify"&gt;Pues bien, en mi caso, C++ es el lenguaje que más objetivos cumple respecto a mis necesidades: programas industriales de uso interno a la empresa (para la cadena de producción y para testear productos), programas de demostración de nuestros productos, simuladores, pedazos de código de demo, firmware para nuestros cacharros y firmware de interoperabilidad entre el PC y el aparato (cuando no es el PC el propio aparato), y muy de tarde en tarde alguna aplicación completa o casi completa para algún producto de terceros cuando el producto no tiene nada que ver con nuestra línea principal de productos (es decir, si nos dedicáramos a hacer máquinas para tostar pipas de girasol, esa aplicación podría ser para un mando a distancia).&lt;/p&gt;  &lt;p align="justify"&gt;Como mucho código está compartido entre el PC y el firmware, lo ideal es C++, y C cuando no haya otra posibilidad. Además, la mayoría de cosas que hago está relacionada con protocolos de comunicaciones, y el PC entra para la simulación y verificación de los mismos.&lt;/p&gt;  &lt;p align="justify"&gt;Os pongo un ejemplo. Hace unos meses tuve que implementar una biblioteca aritmética de enteros de 64 bits para un micro de 8 bits. Es decir, teníamos que realizar operaciones entre enteros de 64 bits dentro de un micro de 8 bits, y a lo más que llegaba el compilador con más posibilidades era a trabajar con enteros de 32. No es que ese fuera el objetivo del firmware, sino que varias de sus tareas exigían el uso de ese tipo de operaciones, así como convertir cadenas de texto en enteros y viceversa. La solución impedía el uso de C++ y de algunas clases que hay circulando por ahí, así que era necesaria una implementación con dos enteros de 32 bits unidos en una estructura, todo ello en C y ocupando el menor tamaño de código posible y con la ejecución más rápida.&lt;/p&gt;  &lt;p align="justify"&gt;¿Cómo habríais resuelto vosotros el tema? Una posibilidad era ir probando en el micro mediante el proceso de editar código, compilar en plataforma cruzada, grabar en el micro y depurar con el JTAG… Laborioso, ¿no? Además, está el problema de cómo comprobar si las operaciones han sido correctas o no. &lt;/p&gt;  &lt;p align="justify"&gt;Ahí es donde entra el PC de lleno. La solución consistió en hacer un programa en estricto C (para que luego el compilador embebido tragara sin problemas) y mezclarlo con código en C++ que, aprovechando que el PC sí que es capaz de trabajar con enteros de 64 bits, comprobara la salida del otro código. Otro problema es el dominio de la aplicación. Si no compruebo todas las combinaciones posibles pudiera ocurrir que el programa fallara con alguna combinación de números, por lo que se requería una prueba bastante exhaustiva aunque no completa porque no es viable comprobar todas las combinaciones aritméticas (suma, resta, multiplicación y división) de cualesquiera dos enteros de 64 bits. Entre las comprobaciones hay que tener en cuenta las operaciones entre dos números muy pequeños, dos muy grandes con y sin desbordamiento, uno grande y uno pequeño en ambos lados, también con y sin desbordamiento, y sobre todo en la franja en la que el resultado y los operandos están en el entorno del salto de los que caben en 32 bits a los más bajos de 64…&lt;/p&gt;  &lt;p align="justify"&gt;Dicho y hecho, tras unos cuatro mil trillones de números generados aleatoriamente con conocimiento de causa (siguiendo las reglas descritas arriba) y un fin de semana de un Q4 al 100% de CPU, comprobamos que la biblioteca no tenía errores o estaba más lo más cerca posible de no tenerlos, de hecho descubrimos código profesional que hay suelto por ahí que en determinadas circunstancias falla, pero esa es otra historia.&lt;/p&gt;  &lt;p align="justify"&gt;Una vez colocado en el micro junto al resto del firmware comprobamos que… ¡fallaba miserablemente! De hecho era completamente incapaz de generar una sola operación correcta. Tras una investigación descubrimos que lo que fallaba no era nuestro programa, sino la biblioteca de enteros de 32 bits del compilador y el propio compilador, que no era capaz de trabajar ni con una estructura de dos enteros de 16 bits lado a lado ni con sus punteros. Esa también es otra historia que no viene al caso y que se solucionó simplificando el código (separando operaciones complejas de multiplicación más suma de enteros de 32 bits en operaciones más sencillas con datos intermedios) y usando variables globales separadas en lugar de estructuras.&lt;/p&gt;  &lt;p align="justify"&gt;En resumen, para que eso funcionara tuvimos que tirar a la basura los conceptos de ocultación de datos, genericidad y abstracción. Hicimos un proyecto de demo con los problemas del compilador y de la biblioteca, se lo enviamos al fabricante del compilador y… ¿Habéis recibido vosotros respuesta? Nosotros tampoco.&lt;/p&gt;  &lt;p align="justify"&gt;Esta entrada continuará la semana que viene.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=168624" width="1" height="1"&gt;</content><author><name>RFOG</name><uri>http://geeks.ms/members/RFOG/default.aspx</uri></author></entry><entry><title>¿Por qué uso C++? (I)</title><link rel="alternate" type="text/html" href="/blogs/rfog/archive/2010/03/10/191-por-qu-233-uso-c-i.aspx" /><id>/blogs/rfog/archive/2010/03/10/191-por-qu-233-uso-c-i.aspx</id><published>2010-03-10T12:51:00Z</published><updated>2010-03-10T12:51:00Z</updated><content type="html">&lt;p align="justify"&gt;Hace poco me preguntaron que contara mis experiencias en mi trabajo con C y C++. Y eso lo hacen no solo aqu&amp;iacute;, sino que muchas veces me lo preguntan en la Vida Real&amp;trade;, y la verdad es que lo tengo bastante dif&amp;iacute;cil, porque considero que no tengo &lt;i&gt;experiencias&lt;/i&gt; con &amp;eacute;l, y cuando las tengo no puedo (ni debo) hablar de ellas, as&amp;iacute; que voy a intentar acercarme lo m&amp;aacute;s posible a lo deseado, sabiendo que no voy a poder explicarme bien y que posiblemente levante alguna que otra pol&amp;eacute;mica.&lt;/p&gt;
&lt;p align="justify"&gt;Para mi C++ es &lt;i&gt;el lenguaje&lt;/i&gt;. As&amp;iacute; muy, pero que muy por encima, conozco Visual Basic (el cl&amp;aacute;sico y el moderno), supongo que podr&amp;iacute;a leer y medio interpretar un programa escrito con ellos, lo mismo que con Pascal por mi herencia de C++ Builder. Algo s&amp;eacute; de Java, sobre todo de cuando sali&amp;oacute;, y en mis tiempos mozos program&amp;eacute; con dBase y luego con Clipper. En su momento sab&amp;iacute;a Cobol (que olvid&amp;eacute; al momento de hacer el examen) y era bastante productivo con los ficheros .BAT, haciendo verdaderas virguer&amp;iacute;as. Tambi&amp;eacute;n sab&amp;iacute;a varios ensambladores, entre ellos el del Z80, x86 y 80x31.&lt;/p&gt;
&lt;p align="justify"&gt;Los lenguajes que conozco bien son C, C++ y C#. Y sus idiomas, es decir, Visual C++, C++ Builder, Windows CE (que incluye a Windows Mobile), MFC, Win32 y .NET. Tambi&amp;eacute;n he hecho mis pinitos con C y Linux, algo de las APIs de GTK y de KDE. Ahora estoy indeciso si seguir con QT o profundizar m&amp;aacute;s en MFC&amp;hellip; QT me tienta mucho, pero mucho de verdad, sin embargo lo veo como demasiado inseguro, sobre todo desde que lo ha cogido Nokia y est&amp;aacute; sacando versi&amp;oacute;n tras versi&amp;oacute;n cada cuatro meses, a pi&amp;ntilde;&amp;oacute;n fijo, est&amp;eacute; como est&amp;eacute; el producto, y as&amp;iacute; est&amp;aacute; acumulando bugs y problemas. Otra cosa que no me mola de QT es que con la versi&amp;oacute;n LGPL no puedo enlazar est&amp;aacute;ticamente, sino que tengo que distribuir las DLLs adecuadas como &lt;i&gt;runtimes&lt;/i&gt;, y para &lt;i&gt;runtimes&lt;/i&gt; ya tenemos bastante con los de Visual C++ y su pu&amp;ntilde;etero &lt;i&gt;DLL Hell&lt;/i&gt;, y tampoco es cuesti&amp;oacute;n de distribuir 300 megas de &lt;i&gt;runtimes&lt;/i&gt; cada cuatro meses. Sin embargo, una de las cosas por las que QT brilla con luz propia es que soporta una enorme cantidad de plataformas como Windows CE, Symbian, MAC, Linux, Windows&amp;hellip;&lt;/p&gt;
&lt;p align="justify"&gt;Tambi&amp;eacute;n tengo bastante experiencia en programar hardware sin sistema operativo, mayormente en C porque muchas veces no hay compilador de C++. De todo lo que hago es lo que menos me gusta m&amp;aacute;s que nada porque tengo que usar C y veo las enorm&amp;iacute;simas limitaciones que tiene frente a su hermano mayor. Cosas que se podr&amp;iacute;an solucionar de un plumazo (es un decir) con una jerarqu&amp;iacute;a de clases y polimorfismo las tengo que hacer con &lt;i&gt;arrays&lt;/i&gt; de punteros a funciones, sentencias &lt;i&gt;switch&lt;/i&gt; y otras zarandajas (que, entre nosotros y sin que nadie m&amp;aacute;s se entere, es lo que termina haciendo el compilador de C++ pero de forma transparente para el programador). Tampoco me gusta mucho tener que pelearme con la configuraci&amp;oacute;n de los registros del micro ni el estudio de los &lt;i&gt;datasheet&lt;/i&gt; que eso conlleva, etc. Adem&amp;aacute;s, la mayor&amp;iacute;a de compiladores de C no son est&amp;aacute;ndar y ni siquiera lo cumplen. No es que traigan extensiones, que son de desear para algunas cosas como definir interrupciones o colocar variables en ROM, RAM, FLASH o registros, sino que, dependiendo del fabricante y el micro de destino, muchas cosas funcionan de forma diferente a lo esperado.&lt;/p&gt;
&lt;p align="justify"&gt;Y bajo toda esta experiencia propia no creo que haya nada como C++. Su expresividad, su potencia y su rapidez son inigualables ante cualquier otro lenguaje. Ya s&amp;eacute; que es dif&amp;iacute;cil de aprender, y m&amp;aacute;s todav&amp;iacute;a de usar, pero pilotar aviones tambi&amp;eacute;n lo es y nadie se queja. Y, personalmente, todos esos problemas que tiene la gente con C++ yo no suelo tenerlos. Evidentemente cometo bugs como todo mortal, y a veces me atasco en tonter&amp;iacute;as, pero casi nunca tengo los t&amp;iacute;picos problemas de fugas de memoria y no liberaci&amp;oacute;n de recursos.&lt;/p&gt;
&lt;p align="justify"&gt;Ser&amp;aacute; porque siempre que pongo un &lt;i&gt;new&lt;/i&gt;, pongo un &lt;i&gt;delete&lt;/i&gt;, siempre que hago o modifico el constructor hago el destructor, siempre que llamo a una funci&amp;oacute;n que abre un recurso tambi&amp;eacute;n llamo a la que lo cierra, e intento evitar salir de un m&amp;eacute;todo si no es al final (incluso con &lt;i&gt;gotos&lt;/i&gt;, sobre todo en &lt;i&gt;embedded&lt;/i&gt;), y si lo hago miro hacia arriba para ver qu&amp;eacute; tengo que cerrar/liberar. Y por supuesto uso, all&amp;aacute; donde est&amp;eacute;n, las herramientas de an&amp;aacute;lisis de c&amp;oacute;digo y de detecci&amp;oacute;n de problemas, en las que Visual C++ es inigualable y a veces te dan una grata sorpresa, ya sea por la genialidad a la hora de detectarte un sibilino potencial problema o por la de mostrarte algo verdaderamente est&amp;uacute;pido y sin sentido.&lt;/p&gt;
&lt;p align="justify"&gt;C++ es para mi &lt;i&gt;la herramienta&lt;/i&gt;, el s&amp;uacute;mmum de todos los lenguajes compilados de programaci&amp;oacute;n, y hasta la fecha no hay ning&amp;uacute;n otro que lo supere. De hecho, siempre lo he dicho y lo repito cada vez que tengo oportunidad: si te has propuesto aprender C++ y no has podido es porque eres mal programador. No hay otra. Lo que s&amp;iacute; entiendo es que C++ no sea adecuado para todo, ni de lejos. Entiendo que si vas a hacer una aplicaci&amp;oacute;n de bases de datos t&amp;iacute;pica, C++ queda un poco&amp;hellip; digamos&amp;hellip; peque&amp;ntilde;o. No peque&amp;ntilde;o en cuanto a caracter&amp;iacute;sticas, sino peque&amp;ntilde;o en su fijaci&amp;oacute;n por el detalle, porque seamos serios: C++, con una buena biblioteca de acceso a bases de datos, podr&amp;iacute;a ser insuperable. Y si no que se lo pregunten a Clipper. [Para el que no lo sepa, Clipper era un front-end con sintaxis similar a dBase generalmente simulada con macros que pasaba a C y que luego se generaba un p-code que era interpretado por un runtime. De hecho pod&amp;iacute;as compilar bloques de c&amp;oacute;digo y guardarlos en una tabla como p-code, que luego era interpretado y ejecutado por el motor principal &amp;ndash;m&amp;aacute;s o menos lo que son ahora los operadores delta]. Y si con C se pod&amp;iacute;a hacer eso, ya no os digo con C++ y una biblioteca similar.&lt;/p&gt;
&lt;p align="justify"&gt;Alguno podr&amp;iacute;a pensar que la incapacidad de aprender a programar C++ podr&amp;iacute;a venir de la dificultad y abstrusismo del propio lenguaje, pero os puedo asegurar que no es as&amp;iacute;. Podr&amp;iacute;a compararlo con el &amp;aacute;lgebra y el c&amp;aacute;lculo. Un lenguaje como C# o Java es &amp;aacute;lgebra, mientras que C++ es an&amp;aacute;lisis. Hay muchas cosas que se pueden hacer con la primera, pero hay otras que o bien son muy dif&amp;iacute;ciles o bien completamente imposibles. Imagina que necesitas obtener los par&amp;aacute;metros de una curva. Puedes representarla gr&amp;aacute;ficamente usando el &amp;aacute;lgebra, y ver sus m&amp;aacute;ximos y sus m&amp;iacute;nimos, y calcular una tangente por aproximaci&amp;oacute;n, pero si realmente quieres ver todos sus detalles, obt&amp;eacute;n su derivada primera y segunda, y obtendr&amp;aacute;s la tangente en todos los puntos y sus m&amp;aacute;ximos y m&amp;iacute;nimos&amp;hellip;&lt;/p&gt;
&lt;p align="justify"&gt;Y de igual forma que hay gente que se para en el &amp;aacute;lgebra y es incapaz de seguir con el an&amp;aacute;lisis, tambi&amp;eacute;n hay programadores que son incapaces de avanzar hacia C++, y de igual forma que un matem&amp;aacute;tico que no sepa an&amp;aacute;lisis no ser&amp;aacute; muy buen matem&amp;aacute;tico, un programador que no pueda aprender C++ tampoco ser&amp;aacute; un buen programador. Ojo, he dicho que no &lt;b&gt;pueda aprender&lt;/b&gt;, no he dicho que &lt;b&gt;tenga que usar C++ para todo&lt;/b&gt;.&lt;/p&gt;
&lt;p align="justify"&gt;Tampoco me gustar&amp;iacute;a que se me interpretara como que si no sabes C++ no eres programador. Nada m&amp;aacute;s lejos de mi intenci&amp;oacute;n. Existen y existir&amp;aacute;n much&amp;iacute;simos programadores que son buenos y no saben C++ porque no les haya hecho falta ya que ante todo, est&amp;aacute; el concepto de &lt;i&gt;un lenguaje para cada tarea&lt;/i&gt;, que ya he avanzado un poco m&amp;aacute;s arriba. Yo mismo, de hecho, hago muchas peque&amp;ntilde;as utilidades para consumo propio en C# porque resulta mucho m&amp;aacute;s r&amp;aacute;pido aunque luego el desempe&amp;ntilde;o no sea el ideal, utilidades que me sirven para procesar o convertir datos y que est&amp;aacute;n asociadas a proyectos m&amp;aacute;s grandes. Y tambi&amp;eacute;n tengo aplicaciones completas hechas en C#, tanto p&amp;uacute;blicas (como el zxFortunes) como de uso interno o comercial (que se acompa&amp;ntilde;an con el hardware que vendemos).&lt;/p&gt;
&lt;p align="justify"&gt;Esta entrada continuar&amp;aacute; la &lt;a target="_self" href="http://geeks.ms/blogs/rfog/archive/2010/03/17/191-por-qu-233-uso-c-ii.aspx"&gt;semana que viene&lt;/a&gt;.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=168615" width="1" height="1"&gt;</content><author><name>RFOG</name><uri>http://geeks.ms/members/RFOG/default.aspx</uri></author><category term="c++" scheme="http://geeks.ms/blogs/rfog/archive/tags/c_2B002B00_/default.aspx" /><category term="escariotrop&amp;#237;as gimn&amp;#233;sicas" scheme="http://geeks.ms/blogs/rfog/archive/tags/escariotrop_26002300_237_3B00_as+gimn_26002300_233_3B00_sicas/default.aspx" /><category term="rationale" scheme="http://geeks.ms/blogs/rfog/archive/tags/rationale/default.aspx" /></entry><entry><title>Hemos leído: Windows Internals 5ª Edición</title><link rel="alternate" type="text/html" href="/blogs/rfog/archive/2010/03/03/hemos-le-237-do-windows-internals-5-170-edici-243-n.aspx" /><id>/blogs/rfog/archive/2010/03/03/hemos-le-237-do-windows-internals-5-170-edici-243-n.aspx</id><published>2010-03-03T12:38:00Z</published><updated>2010-03-03T12:38:00Z</updated><content type="html">&lt;p&gt;&lt;a target="_blank" href="http://www.microsoft.com/learning/en/us/book.aspx?ID=12069&amp;amp;locale=en-us"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;No s&amp;eacute; si es que la memoria me falla, o que tiempos antiguos fueron mejores o que simplemente he mezclado dos libros, pero lo cierto es que este libro me ha reportado m&amp;aacute;s desilusiones que ilusiones. Recuerdo haber le&amp;iacute;do ediciones anteriores (la cuarta seguro que no), aunque en mi biblioteca f&amp;iacute;sica &amp;ndash;la de los libros en papel, vamos-, s&amp;oacute;lo veo el de Helen Custer, que fue, si de nuevo las meninges no me enga&amp;ntilde;an, el primero o la precuela de la serie. Pero lo que no recuerdo es que fuera tan pol&amp;iacute;ticamente correcto, y eso es lo que me ha defraudado de este.&lt;/p&gt;
&lt;p&gt;Porque en el libro no viene nada que no est&amp;eacute; documentado en el DDK, el SDK u otra documentaci&amp;oacute;n emitida por Microsoft, lo &amp;uacute;nico es que, aqu&amp;iacute;, est&amp;aacute; todo reunido de una forma m&amp;aacute;s o menos coherente, organizada y en papel.&lt;/p&gt;
&lt;p&gt;Es evidente que intentar explicar en un libro &amp;ndash;aunque sea de m&amp;aacute;s de 1200 p&amp;aacute;ginas- el funcionamiento de un sistema operativo que tiene m&amp;aacute;s de cincuenta millones de l&amp;iacute;neas de c&amp;oacute;digo es tarea imposible. &lt;/p&gt;
&lt;p&gt;Lo que no esperaba es que fuera tan &lt;i&gt;pol&amp;iacute;ticamente correcto&lt;/i&gt;, tan formalmente estudiado para no resultar inadecuado, ya que seguro muchas de las cosas que se cuentan en &amp;eacute;l no son tal y como se han presentado, o se han omitido. Y estoy seguro de ello, porque en algunas secciones hay huecos y cosas que no est&amp;aacute;n del todo explicadas. Si bien se pueden deber al desconocimiento de los autores, o al recorte de p&amp;aacute;ginas, el texto podr&amp;iacute;a haber sido m&amp;aacute;s fluido. Hay secciones enteras que no son m&amp;aacute;s que un mero recitamiento en plan loro de lo aprendido, en lugar de resultar un continuo coherente. Y de hecho, hay partes que no las he le&amp;iacute;do por aburridas, pesadas y por apuntar a ser un mero listado de caracter&amp;iacute;sticas tal y como se pueden encontrar en una documentaci&amp;oacute;n oficial.&lt;/p&gt;
&lt;p&gt;Y como muestra de lo omitido, un bot&amp;oacute;n: &lt;i&gt;&lt;a href="http://geeks.ms/blogs/rfog/archive/2010/01/06/191-se-fragmenta-el-registro-de-windows.aspx"&gt;&amp;iquest;Se fragmenta el registro de Windows?,&lt;/a&gt;&lt;/i&gt; escrito en este mismo blog. Pues bien, hay muchas secciones as&amp;iacute;, que te dejan con la palabra en la boca, como si s&amp;oacute;lo te hubieran contado lo que han querido&amp;hellip;&lt;/p&gt;
&lt;p&gt;No obstante esas pegas, que pueden enteramente deberse a mi mismo y a que no aceptar&amp;iacute;a la invitaci&amp;oacute;n a un club que me aceptara como socio (parafraseando del mala manera al insigne Groucho), el libro debe ser una gozada para muchos administradores y algunos programadores, ya que te explica muchas cosas que de otro modo quedar&amp;iacute;an al aire o como interpretaci&amp;oacute;n de un curso de sistemas operativos 101.&lt;/p&gt;
&lt;p&gt;As&amp;iacute; mismo, en aquellos casos en los que pienses que el problema no est&amp;aacute; en tu c&amp;oacute;digo o tu script, puedes bucear dentro de las estructuras internas de Windows (all&amp;aacute; donde el libro las explica, que no es en muchos sitios, la verdad) para descubrir d&amp;oacute;nde te has equivocado tras muchas horas de investigar donde no era. &lt;/p&gt;
&lt;p&gt;Y poco m&amp;aacute;s que contar, si quieres ver qu&amp;eacute; trae el libro por dentro, pues te das un voltio por Amazon y miras el &amp;iacute;ndice.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=168613" width="1" height="1"&gt;</content><author><name>RFOG</name><uri>http://geeks.ms/members/RFOG/default.aspx</uri></author><category term="Sistemas Operativos" scheme="http://geeks.ms/blogs/rfog/archive/tags/Sistemas+Operativos/default.aspx" /><category term="windows" scheme="http://geeks.ms/blogs/rfog/archive/tags/windows/default.aspx" /><category term="rationale" scheme="http://geeks.ms/blogs/rfog/archive/tags/rationale/default.aspx" /><category term="libros" scheme="http://geeks.ms/blogs/rfog/archive/tags/libros/default.aspx" /><category term="Win32" scheme="http://geeks.ms/blogs/rfog/archive/tags/Win32/default.aspx" /></entry><entry><title>Qué hacer cuando a Visual C++ se le va la pinza en el editor de diálogos</title><link rel="alternate" type="text/html" href="/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" /><id>/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</id><published>2010-02-17T12:25:00Z</published><updated>2010-02-17T12:25:00Z</updated><content type="html">&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;</content><author><name>RFOG</name><uri>http://geeks.ms/members/RFOG/default.aspx</uri></author><category term="c++" scheme="http://geeks.ms/blogs/rfog/archive/tags/c_2B002B00_/default.aspx" /><category term="Visual Studio" scheme="http://geeks.ms/blogs/rfog/archive/tags/Visual+Studio/default.aspx" /><category term="tips" scheme="http://geeks.ms/blogs/rfog/archive/tags/tips/default.aspx" /><category term="MFC" scheme="http://geeks.ms/blogs/rfog/archive/tags/MFC/default.aspx" /></entry><entry><title>Conversión ANSI a Unicode y viceversa</title><link rel="alternate" type="text/html" href="/blogs/rfog/archive/2010/02/03/conversi-243-n-ansi-a-unicode-y-viceversa.aspx" /><id>/blogs/rfog/archive/2010/02/03/conversi-243-n-ansi-a-unicode-y-viceversa.aspx</id><published>2010-02-03T11:51:00Z</published><updated>2010-02-03T11:51:00Z</updated><content type="html">&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;</content><author><name>RFOG</name><uri>http://geeks.ms/members/RFOG/default.aspx</uri></author><category term="c++" scheme="http://geeks.ms/blogs/rfog/archive/tags/c_2B002B00_/default.aspx" /><category term="tips" scheme="http://geeks.ms/blogs/rfog/archive/tags/tips/default.aspx" /><category term="MFC" scheme="http://geeks.ms/blogs/rfog/archive/tags/MFC/default.aspx" /><category term="Win32" scheme="http://geeks.ms/blogs/rfog/archive/tags/Win32/default.aspx" /></entry><entry><title>Todo lo que quisiste saber sobre las DLL y no te atreviste a preguntar (II)</title><link rel="alternate" type="text/html" href="/blogs/rfog/archive/2010/01/29/todo-lo-que-quisiste-saber-sobre-las-dll-y-no-te-atreviste-a-preguntar-ii.aspx" /><id>/blogs/rfog/archive/2010/01/29/todo-lo-que-quisiste-saber-sobre-las-dll-y-no-te-atreviste-a-preguntar-ii.aspx</id><published>2010-01-29T11:28:00Z</published><updated>2010-01-29T11:28:00Z</updated><content type="html">&lt;p align="justify"&gt;Como pod&amp;eacute;is ver no se me ha &lt;a href="http://geeks.ms/blogs/rfog/archive/2009/06/29/todo-lo-que-quisiste-saber-sobre-las-dll-y-no-te-atreviste-a-preguntar-i.aspx"&gt;olvidado el tema&lt;/a&gt;, simplemente es que he estado demasiado gandulete como para escribir sobre esto, pero una pregunta en el &lt;a href="http://social.msdn.microsoft.com/Forums/es-ES/vcppes/thread/8539bf2a-8510-45fe-9319-d4906d5def27"&gt;foro web de C++&lt;/a&gt; me ha hecho que me ponga a ello. En teor&amp;iacute;a esta deber&amp;iacute;a ser la tercera parte en lugar de la segunda, aunque la verdad no es que realmente tenga mucha importancia. Por lo tanto, esta entrada que est&amp;aacute;s leyendo sigue a &lt;a href="http://geeks.ms/blogs/rfog/archive/2009/06/29/todo-lo-que-quisiste-saber-sobre-las-dll-y-no-te-atreviste-a-preguntar-i.aspx"&gt;esta&lt;/a&gt; otra.&lt;/p&gt;
&lt;p align="justify"&gt;Aqu&amp;iacute; voy a contar los tres modos que hay de usar una DLL desde C y C++, aunque solo voy a explicar dos de ellos porque el tercero digamos que viene de las primeras versiones de Windows y ni siquiera s&amp;eacute; si los compiladores modernos la soportan.&lt;/p&gt;
&lt;p align="justify"&gt;Pero antes, una introducci&amp;oacute;n.&lt;/p&gt;
&lt;p align="justify"&gt;&lt;strong&gt;&lt;span style="text-decoration:underline;"&gt;&amp;iquest;Qu&amp;eacute; necesito para usar una DLL de terceros?&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p align="justify"&gt;Cuando vamos a usar una DLL, ya sea nuestra o de terceros, se nos deben suministrar al menos tres archivos. El primero, que no nos har&amp;iacute;a falta para el segundo m&amp;eacute;todo, es un fichero cabecera conteniendo los prototipos de las exportaciones de la DLL, es decir, las firmas de las funciones y la declaraci&amp;oacute;n de los tipos contenidos.&lt;/p&gt;
&lt;p align="justify"&gt;En general, el formato de cada prototipo debe seguir de cerca el siguiente formato:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p align="justify"&gt;__declspec(dllexport) __stdcall int HazAlgo(int algo);&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p align="justify"&gt;O&lt;/p&gt;
&lt;blockquote&gt;
&lt;p align="justify"&gt;extern &amp;ldquo;C&amp;rdquo; __declspec(dllexport) int HazAlgo(int algo);&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p align="justify"&gt;La primera firma declara una funci&amp;oacute;n con formato de llamada est&amp;aacute;ndar (el &lt;i&gt;__stdcall&lt;/i&gt;) que pertenece a una DLL y que resulta exportado, es decir, que podemos usar. La segunda declara lo mismo pero con el protocolo de llamada de C, que tambi&amp;eacute;n podr&amp;iacute;amos haber puesto como &lt;i&gt;__cdecl&lt;/i&gt;. Del protocolo de llamada ya habl&amp;eacute; en la entrada anterior, y en general todos los compiladores de C y C++ deber&amp;iacute;an entender ambas declaraciones, y si no lo hacen seguro que tienen expresiones similares.&lt;/p&gt;
&lt;p align="justify"&gt;El segundo fichero es lo que se conoce como biblioteca de importaci&amp;oacute;n, que es un archivo con la extensi&amp;oacute;n .lib, con la diferencia de que, en este caso, en lugar de contener las propias funciones como en una biblioteca normal, lo que contiene son las firmas de las funciones exportadas y c&amp;oacute;mo est&amp;aacute;n relacionadas con la propia DLL.&lt;/p&gt;
&lt;p align="justify"&gt;En el mundo Windows existen dos formatos de ficheros .lib: el COFF, que es el que usa Microsoft y compiladores compatibles y el OMF, que es el que usan otros compiladores como el C++Builder. Generalmente todos los compiladores suelen venir con una herramienta de conversi&amp;oacute;n de formato.&lt;/p&gt;
&lt;p align="justify"&gt;Y finalmente necesitamos la DLL y todas sus dependencias si las hubiera.&lt;/p&gt;
&lt;p align="justify"&gt;En general muchas veces no es necesario recompilar el c&amp;oacute;digo de nuestra aplicaci&amp;oacute;n cada vez que se modifique la DLL si no hemos cambiado nada de la parte p&amp;uacute;blica. Creo que incluso si se a&amp;ntilde;aden funciones a la DLL tampoco es necesario recompilar siempre y cuando no se cambie ninguna declaraci&amp;oacute;n de las existentes y enlazadas.&lt;/p&gt;
&lt;p align="justify"&gt;&lt;strong&gt;&lt;span style="text-decoration:underline;"&gt;Primer m&amp;eacute;todo: el f&amp;aacute;cil&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p align="justify"&gt;El m&amp;eacute;todo m&amp;aacute;s sencillo para usar una DLL en nuestro c&amp;oacute;digo en C o C++ es a&amp;ntilde;adir la biblioteca de importaci&amp;oacute;n (el fichero .lib) a las dem&amp;aacute;s bibliotecas en nuestro proyecto, lo que se suele hacer en las opciones del enlazador.&lt;/p&gt;
&lt;p align="justify"&gt;Luego incluimos el fichero cabecera en donde nos haga falta y ya est&amp;aacute; todo hecho: tan s&amp;oacute;lo debemos llamar a las funciones de la DLL como si fueran funciones normales y corrientes.&lt;/p&gt;
&lt;p align="justify"&gt;Debemos tener en cuenta que si la DLL contiene clases o tipos no est&amp;aacute;ndar, quiz&amp;aacute;s el enlazador sea incapaz de encontrar los nombres porque cada compilador de C++ ofusca el nombre de las funciones de una manera diferente, y en ese caso s&amp;oacute;lo nos queda la opci&amp;oacute;n de o bien pedir una DLL compatible con nuestro compilador o bien hacer un &lt;i&gt;strip&lt;/i&gt; del fichero LIB, ver c&amp;oacute;mo se llaman en realidad las funciones, y hacernos nosotros mismos el fichero cabecera. No os lo recomiendo.&lt;/p&gt;
&lt;p align="justify"&gt;El &amp;uacute;ltimo paso es dejar la DLL en una ruta que nuestro programa sea capaz de encontrar, como el directorio donde se est&amp;aacute; ejecutando o en alg&amp;uacute;n camino disponible en el PATH.&lt;/p&gt;
&lt;p align="justify"&gt;&lt;strong&gt;&lt;span style="text-decoration:underline;"&gt;Segundo m&amp;eacute;todo: carga din&amp;aacute;mica&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p align="justify"&gt;No lo he dicho antes, pero cuando se usa el primer m&amp;eacute;todo, las DLL se cargan de forma autom&amp;aacute;tica a la vez que nuestra aplicaci&amp;oacute;n, y siguen en memoria hasta que salimos. &lt;/p&gt;
&lt;p align="justify"&gt;Existe una forma de carga manual un poco m&amp;aacute;s laboriosa, pero que nos permite cosas como la carga din&amp;aacute;mica de temas, de extensiones, de plugins o de diferentes versiones de una misma DLL. &lt;/p&gt;
&lt;p align="justify"&gt;Supongamos que tenemos una DLL con las cadenas para cada idioma. Cuando arranquemos nuestra aplicaci&amp;oacute;n miramos qu&amp;eacute; idioma est&amp;aacute; en la configuraci&amp;oacute;n y cargamos manualmente la DLL adecuada. Es lo que hace autom&amp;aacute;ticamente el sistema MUI de Windows y la internacionalizaci&amp;oacute;n en .NET y otros lenguajes. Pues de igual forma que se hace autom&amp;aacute;ticamente, se puede hacer manualmente.&lt;/p&gt;
&lt;p align="justify"&gt;Para este m&amp;eacute;todo s&amp;oacute;lo necesitamos la DLL en cuesti&amp;oacute;n y la lista de prototipos de funciones. Lo primero es hacernos un puntero a funci&amp;oacute;n de cada una de las funciones de la DLL:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p align="justify"&gt;int (__stdcall *pHazAlgo)(int);&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p align="justify"&gt;Luego llamamos a la funci&amp;oacute;n de Win32 &lt;i&gt;&lt;a target="_blank" href="http://msdn.microsoft.com/en-us/library/ms684175(VS.85).aspx"&gt;LoadLibrary()&lt;/a&gt;&lt;/i&gt; pas&amp;aacute;ndole la cadena en donde est&amp;aacute; la DLL que queramos cargar. La funci&amp;oacute;n nos devolver&amp;aacute; un HINSTANCE, que si todo ha ido bien ser&amp;aacute; diferente de NULL. Entonces, para cada una de las funciones de la DLL, la cargamos sobre nuestro puntero mediante &lt;i&gt;&lt;a target="_blank" href="http://msdn.microsoft.com/en-us/library/ms683212(VS.85).aspx"&gt;GetProcAddress()&lt;/a&gt;&lt;/i&gt; pas&amp;aacute;ndole el HINSTANCE y la cadena con el nombre de la funci&amp;oacute;n en la DLL:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p align="justify"&gt;pHazAlgo=GetProcAddress(hLib,&amp;rdquo;HazAlgo&amp;rdquo;);&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p align="justify"&gt;Ahora tendremos un puntero a funci&amp;oacute;n (que realmente es un doble puntero, porque ese puntero apunta a una tabla dentro de la DLL que a su vez apunta a la funci&amp;oacute;n real). Con ese puntero podemos llamar a la funci&amp;oacute;n sin problemas:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p align="justify"&gt;int respuesta=pHazAlgo(3);&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p align="justify"&gt;Quiz&amp;aacute;s tengas que hacer alg&amp;uacute;n tipo de moldeo en la llamada a &lt;i&gt;GetProcAddress()&lt;/i&gt;.&lt;/p&gt;
&lt;p align="justify"&gt;Cuando queramos descargar de memoria esta DLL, llamamos a &lt;i&gt;&lt;a target="_blank" href="http://msdn.microsoft.com/en-us/library/ms683152(VS.85).aspx"&gt;FreeLibrary()&lt;/a&gt;&lt;/i&gt; y ser&amp;aacute; descargada. Nuestros punteros seguir&amp;aacute;n asignados, pero apuntar&amp;aacute;n a ning&amp;uacute;n sitio, por lo que si volvemos a necesitar la DLL (u otra versi&amp;oacute;n de la misma) deberemos repetir el proceso.&lt;/p&gt;
&lt;p align="justify"&gt;&lt;strong&gt;&lt;span style="text-decoration:underline;"&gt;Tercer m&amp;eacute;todo: ordinales y ficheros DEF&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p align="justify"&gt;Este es el que no voy a explicar porque es muy antiguo y ni siquiera s&amp;eacute; si sigue siendo v&amp;aacute;lido. Antiguamente las funciones dentro de las DLL se guardaban numeradas. Es decir, en lugar de guardar una cadena con el nombre y un puntero a la relaci&amp;oacute;n relativa dentro del fichero en los metadatos de la DLL, se guardaba un array de punteros que apuntaba a cada una de las funciones. &lt;/p&gt;
&lt;p align="justify"&gt;Luego se ten&amp;iacute;a un fichero DEF que pon&amp;iacute;a el nombre de la funci&amp;oacute;n y el ordinal que ten&amp;iacute;a dentro de la DLL (la posici&amp;oacute;n dentro de ese array), de forma que cuando se compilaba un programa para una DLL de este tipo (usando el fichero DEF en lugar del LIB), se dejaba un array de punteros a funciones que el cargador pareaba con el de la DLL&amp;hellip; &lt;/p&gt;
&lt;p align="justify"&gt;Ya os pod&amp;eacute;is imaginar la que se pod&amp;iacute;a armar si por cualquier motivo ese orden era cambiado por el compilador. El que faltara un ordinal simplemente lanzaba un error, pero el que se cambiara uno por otro pod&amp;iacute;a terminar tumbando no solo nuestra aplicaci&amp;oacute;n, sino Windows al completo, ya que en aquella &amp;eacute;poca las DLL s&amp;oacute;lo se cargaban una vez y eran usadas y compartidas por todas las aplicaciones que la requer&amp;iacute;an, sistema operativo incluido.&lt;/p&gt;
&lt;p align="justify"&gt;Esto se hac&amp;iacute;a as&amp;iacute; porque con la velocidad de los procesadores de aquellos a&amp;ntilde;os, el tiempo para buscar la cadena con la funci&amp;oacute;n en los metadatos y parearla con el puntero correspondiente consum&amp;iacute;a una gran cantidad de tiempo, sobre todo si hab&amp;iacute;a muchas funciones dentro de una DLL, y en la forma de ordinales tan s&amp;oacute;lo hab&amp;iacute;a que copiar punteros en bucle.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=166163" width="1" height="1"&gt;</content><author><name>RFOG</name><uri>http://geeks.ms/members/RFOG/default.aspx</uri></author><category term="c++" scheme="http://geeks.ms/blogs/rfog/archive/tags/c_2B002B00_/default.aspx" /><category term="Sistemas Operativos" scheme="http://geeks.ms/blogs/rfog/archive/tags/Sistemas+Operativos/default.aspx" /><category term="windows" scheme="http://geeks.ms/blogs/rfog/archive/tags/windows/default.aspx" /><category term="Win32" scheme="http://geeks.ms/blogs/rfog/archive/tags/Win32/default.aspx" /></entry><entry><title>Obtener el propio número de versión desde MFC y Win32 (y II)</title><link rel="alternate" type="text/html" href="/blogs/rfog/archive/2010/01/26/obtener-el-propio-n-250-mero-de-versi-243-n-desde-mfc-y-win32-y-ii.aspx" /><id>/blogs/rfog/archive/2010/01/26/obtener-el-propio-n-250-mero-de-versi-243-n-desde-mfc-y-win32-y-ii.aspx</id><published>2010-01-26T12:30:41Z</published><updated>2010-01-26T12:30:41Z</updated><content type="html">&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;</content><author><name>RFOG</name><uri>http://geeks.ms/members/RFOG/default.aspx</uri></author><category term="c++" scheme="http://geeks.ms/blogs/rfog/archive/tags/c_2B002B00_/default.aspx" /><category term="Sistemas Operativos" scheme="http://geeks.ms/blogs/rfog/archive/tags/Sistemas+Operativos/default.aspx" /><category term="windows" scheme="http://geeks.ms/blogs/rfog/archive/tags/windows/default.aspx" /><category term="tips" scheme="http://geeks.ms/blogs/rfog/archive/tags/tips/default.aspx" /><category term="Win32" scheme="http://geeks.ms/blogs/rfog/archive/tags/Win32/default.aspx" /></entry><entry><title>Instalar el SDK del iRex DR1000S en Linux (Ubuntu 9.10 Karmic Koala)</title><link rel="alternate" type="text/html" href="/blogs/rfog/archive/2010/01/21/instalar-el-sdk-del-irex-dr1000s-en-linux-ubuntu-9-10-karmic-koala.aspx" /><id>/blogs/rfog/archive/2010/01/21/instalar-el-sdk-del-irex-dr1000s-en-linux-ubuntu-9-10-karmic-koala.aspx</id><published>2010-01-21T17:37:00Z</published><updated>2010-01-21T17:37:00Z</updated><content type="html">&lt;p&gt;Ya sab&amp;eacute;is qu&amp;eacute; poco me gusta Linux, pero a veces tiene su inter&amp;eacute;s, o m&amp;aacute;s bien me da por tom&amp;aacute;rmelo sin m&amp;aacute;s. A&amp;ntilde;adamos que Ubuntu no es que sea de muy de mi agrado y tendremos la perrer&amp;iacute;a m&amp;aacute;s absoluta en investigar sobre todo eso.&lt;/p&gt;
&lt;p&gt;Pero resulta que s&amp;iacute; tengo otra pasi&amp;oacute;n, y es la de los aparatos equipados con pantallas de tinta-e, y la mayor&amp;iacute;a de ellos &amp;ndash;por no decir todos- llevan en sus tripas Linux, y si alg&amp;uacute;n fabricante saca alg&amp;uacute;n SDK este seguro que va a ejecutarse bajo dicho sistema operativo.&lt;/p&gt;
&lt;p&gt;Los productos de la empresa iRex tendr&amp;aacute;n muchas pegas y deficiencias en cuanto al software, pero lo que s&amp;iacute; es cierto es que se toman muy en serio el Open Source. Cuando abandonaron el desarrollo del iLiad, publicaron todo el c&amp;oacute;digo fuente completo, y el DR1000S tiene su SDK e incluso su emulador. Esperemos que el reci&amp;eacute;n salido DR800S tambi&amp;eacute;n cuente con &amp;eacute;l.&lt;/p&gt;
&lt;p&gt;Bueno, pues el otro d&amp;iacute;a me dio por intentar, por en&amp;eacute;sima vez, instalarme el citado SDK dentro de una Ubuntu. En su momento, con la versi&amp;oacute;n adecuada y la documentaci&amp;oacute;n oficial, no consegu&amp;iacute; hacerlo funcionar, as&amp;iacute; que menos con una versi&amp;oacute;n m&amp;aacute;s moderna. Pero me pic&amp;oacute; el gusano y me puse a ello. Y lo consegu&amp;iacute; tras muchos sudores y esfuerzos.&lt;/p&gt;
&lt;p&gt;Pero primero lo que ya existe. La descarga oficial del c&amp;oacute;digo fuente y de los SDK est&amp;aacute; aqu&amp;iacute;: &lt;a href="http://developer.irexnet.com/pub/iOn/"&gt;http://developer.irexnet.com/pub/iOn/&lt;/a&gt;. Tan s&amp;oacute;lo tienes que buscar la versi&amp;oacute;n adecuada. En el momento en el que escribo esto, es la versi&amp;oacute;n 1.7 para el SDK y 1.7.1 para el c&amp;oacute;digo fuente. Las instrucciones para instalarlo est&amp;aacute;n &lt;a href="http://developer.irexnet.com/pub/iOn/SDK/iOn%20Development%20Environment.pdf"&gt;aqu&amp;iacute;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;En Mobileread hay una imagen con Ubuntu lista para utilizar, en &lt;a href="http://www.mobileread.com/forums/showthread.php?t=37883"&gt;este&lt;/a&gt; hilo. No s&amp;eacute; qu&amp;eacute; versi&amp;oacute;n de SDK traer&amp;aacute;, seguro que una antigua, pero simplemente hay que quitar el viejo y poner el nuevo. Cosas que no me molan de esa imagen es que la versi&amp;oacute;n de Anjuta es muy vieja, as&amp;iacute; como el propio Ubuntu, pero para quien s&amp;oacute;lo quiera echarle un vistazo r&amp;aacute;pido le ser&amp;aacute; suficiente.&lt;/p&gt;
&lt;p&gt;Si quieres seguir esta entrada con detalle, ahora es el momento de echarle un vistazo a los primeros puntos del documento de la instalaci&amp;oacute;n. Yo cog&amp;iacute; mi vmWare e instal&amp;eacute; la &amp;uacute;ltima versi&amp;oacute;n de Ubuntu, y aunque el manual diga que el SDK no funciona dentro de un sistema operativo virtualizado, no es as&amp;iacute;, no al menos en mi Windows 7 x64 con 8 GB de RAM. Y para que la VM no ande escasa, le he asignado 2GB de RAM.&lt;/p&gt;
&lt;p&gt;Una vez instalada la distro, &lt;b&gt;no a&amp;ntilde;adas el repositorio de la secci&amp;oacute;n 2.2&lt;/b&gt;, en lugar de ello haremos algunas cosas &lt;i&gt;a mano&lt;/i&gt;. Si intentas seguir el documento te vas a encontrar con un Anjuta y un Poki que no van a funcionar.&lt;/p&gt;
&lt;p&gt;Instalemos Anjuta y Anjuta-dev desde los repositorios normales. Una vez hecho eso instalaremos, a mano, los plugins de Anjuta Extras, que tendr&amp;aacute;s que bajar en c&amp;oacute;digo fuente de aqu&amp;iacute;: &lt;a href="http://projects.gnome.org/anjuta/downloads.shtml"&gt;http://projects.gnome.org/anjuta/downloads.shtml&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Yo me he creado una carpeta dependiente de mi home con el nombre de &amp;ldquo;dr1000s&amp;rdquo;, y ah&amp;iacute; dentro he puesto otra nueva llamada &amp;ldquo;dependencies&amp;rdquo;, que es donde voy a colocar el c&amp;oacute;digo fuente dependiente para que me funcione todo bien.&lt;/p&gt;
&lt;p&gt;Descomprime e instala los Extras (ya sabes: ./configure, make, sudo make install), y si no sabes de qu&amp;eacute; estoy hablando mejor te coges la imagen ya preparada.&lt;/p&gt;
&lt;p&gt;***&lt;/p&gt;
&lt;p&gt;Ahora viene el tinglado gordo. En la p&amp;aacute;gina de arriba hay una serie de plugins, tenemos que instalar, a mano, el &lt;i&gt;Poky SDK Plugin&lt;/i&gt;, que va por la versi&amp;oacute;n 0.5 y &lt;b&gt;no es compatible con las versiones modernas de Anjuta&lt;/b&gt;, que es el problema que tendr&amp;iacute;amos si sigui&amp;eacute;ramos las instrucciones de la documentaci&amp;oacute;n original.&lt;/p&gt;
&lt;p&gt;Tenemos que bajarnos el c&amp;oacute;digo, descomprimirlo e intentar compilarlo. Igual que a mi, os va a dar docenas de errores, que hay que ir corrigiendo a mano, ya que el API de desarrollo de Anjuta ha variado y hay funciones que cambian de par&amp;aacute;metros y otras que no existen, cosa que mola mucho y parece que nadie aprende a evitar. Si tienes un API y necesitas crear otro nuevo, no llames a las funciones iguales, o bien mantienes el viejo y creas nuevas funciones o bien creas las nuevas y abandonas las viejas.&lt;/p&gt;
&lt;p&gt;Tambi&amp;eacute;n hay otro problema con el paquete gnome-vfs, que parece que ha cambiado de lugar o que el configurador del Poky SDK es incapaz de encontrar, el tema est&amp;aacute; en que hay que modificar una buena cantidad de c&amp;oacute;digo. Traste&amp;eacute; tanto que al final ya no recuerdo qu&amp;eacute; cambi&amp;eacute;.&lt;/p&gt;
&lt;p&gt;Una cosa que tienes que hacer es copiar el contenido de /usr/include/gnome-vfs-2.0/gnomevfs en /usr/include/gnomevfs en tu distro. Ya s&amp;eacute; que es una chapuza, que lo que hay que hacer es a&amp;ntilde;adir las rutas en la configuraci&amp;oacute;n del proyecto, pero yo al menos no s&amp;eacute; d&amp;oacute;nde se hace eso.&lt;/p&gt;
&lt;p&gt;Bueno, en &lt;a href="http://www.mobileread.com/forums/showthread.php?t=70387"&gt;este&lt;/a&gt; hilo de Mobileread tienes el c&amp;oacute;digo fuente que modifiqu&amp;eacute;, listo para un sudo &lt;i&gt;make install&lt;/i&gt;&amp;hellip; Y lo pongo as&amp;iacute; porque hay que modificar un makefile generado por el &lt;i&gt;configure&lt;/i&gt;, pero como de nuevo no s&amp;eacute; d&amp;oacute;nde hay que a&amp;ntilde;adir la l&amp;iacute;nea, lo hice en el makefile final.&lt;/p&gt;
&lt;p&gt;El tema est&amp;aacute; jodido, porque aparte de tener que a&amp;ntilde;adir inclusiones nuevas, he tenido que poner una buena espuerta de NULL en las funciones que reciben nuevos par&amp;aacute;metros, y comentar otras llamadas a funciones que ya no existen en Anjuta, de modo que lo mismo he hecho una bomba de relojer&amp;iacute;a&amp;hellip; Si quieres ver qu&amp;eacute; he cambiado, puedes hacer una comparaci&amp;oacute;n de los ficheros originales del Poky SDK con los que yo he modificado.&lt;/p&gt;
&lt;p&gt;En fin, el tema est&amp;aacute; en que siguiendo estas instrucciones y las del propio documento, tendr&amp;aacute;s instalado tu SDK y tu emulador para desarrollar c&amp;oacute;digo para el DR1000 desde el IDE de Anjuta, con integraci&amp;oacute;n de todo y en un Ubuntu bastante m&amp;aacute;s moderno y funcional que la imagen original.&lt;/p&gt;
&lt;p&gt;Lo que no he conseguido ha sido lanzar el depurador desde el IDE, cosa que queda pendiente para otro momento. Quiz&amp;aacute;s cuando lo consiga publique la imagen en alg&amp;uacute;n lado.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=165664" width="1" height="1"&gt;</content><author><name>RFOG</name><uri>http://geeks.ms/members/RFOG/default.aspx</uri></author><category term="c++" scheme="http://geeks.ms/blogs/rfog/archive/tags/c_2B002B00_/default.aspx" /><category term="escariotrop&amp;#237;as gimn&amp;#233;sicas" scheme="http://geeks.ms/blogs/rfog/archive/tags/escariotrop_26002300_237_3B00_as+gimn_26002300_233_3B00_sicas/default.aspx" /><category term="Sistemas Operativos" scheme="http://geeks.ms/blogs/rfog/archive/tags/Sistemas+Operativos/default.aspx" /><category term="linux" scheme="http://geeks.ms/blogs/rfog/archive/tags/linux/default.aspx" /><category term="chapuzas" scheme="http://geeks.ms/blogs/rfog/archive/tags/chapuzas/default.aspx" /><category term="ebooks" scheme="http://geeks.ms/blogs/rfog/archive/tags/ebooks/default.aspx" /></entry><entry><title>¿Se fragmenta el registro de Windows?</title><link rel="alternate" type="text/html" href="/blogs/rfog/archive/2010/01/06/191-se-fragmenta-el-registro-de-windows.aspx" /><id>/blogs/rfog/archive/2010/01/06/191-se-fragmenta-el-registro-de-windows.aspx</id><published>2010-01-06T13:22:00Z</published><updated>2010-01-06T13:22:00Z</updated><content type="html">&lt;p align="justify"&gt;La respuesta corta es que s&amp;iacute;. La larga es que no mucho. Veamos.&lt;/p&gt;
&lt;p align="justify"&gt;Acabo de terminar de leer la parte del libro de &lt;i&gt;Windows Internals&lt;/i&gt; que se refiere al registro de Windows, y b&amp;aacute;sicamente me ha quedado un mal sabor de boca, cosa que a veces suele pasar con este tipo de libros &lt;i&gt;pol&amp;iacute;ticamente aprobados&lt;/i&gt;, y es que no deja nada claro si el registro se fragmenta o no.&lt;/p&gt;
&lt;p align="justify"&gt;En disco, el registro no es m&amp;aacute;s que una serie de ficheros repartidos a lo largo de varios lugares, ficheros que se corresponden con las diferentes ramas del mismo. La mayor ventaja de Vista y siguientes frente a XP es que ahora existe un juego de llamadas a funci&amp;oacute;n que realizar&amp;aacute;n operaciones transaccionales sobre el mismo. Es decir, igual que en las bases de datos &amp;ndash;y el registro no deja de ser una-, iniciamos una transacci&amp;oacute;n, realizamos una serie de acciones y si las completamos bien, cerramos dicha transacci&amp;oacute;n, y si no, la abortamos. Para los programas instaladores esta caracter&amp;iacute;stica es cojonuda, y a veces tambi&amp;eacute;n para los programas de usuario. Con s&amp;oacute;lo imaginarnos dejar el registro a medio actualizar a causa de un corte de corriente&amp;hellip;&lt;/p&gt;
&lt;p align="justify"&gt;Lo que s&amp;iacute; queda claro es que en memoria la fragmentaci&amp;oacute;n es m&amp;iacute;nima. Es decir, casi da igual el grado de fragmentaci&amp;oacute;n que haya en los archivos (los &lt;i&gt;hive&lt;/i&gt;, como los llaman), cuando estos son cargados a memoria mediante virtualizaci&amp;oacute;n de la misma, la posible fragmentaci&amp;oacute;n queda reducida al m&amp;iacute;nimo. Adem&amp;aacute;s, los valores m&amp;aacute;s com&amp;uacute;nmente accedidos quedan cacheados. Tambi&amp;eacute;n se mantienen listas y cach&amp;eacute;s de escritura, para minimizar la sobrecarga en el sistema, lo que a veces, ante un corte imprevisto de corriente, hace que no se graben dichas modificaciones, aunque Windows garantiza la no corrupci&amp;oacute;n de los &lt;i&gt;hives&lt;/i&gt; mediante un sistema de mapeados y de escrituras en ficheros dobles y triples (m&amp;aacute;s o menos lo mismo que hago yo con los &lt;i&gt;firmwares&lt;/i&gt; cuando los datos no deben corromperse ante un corte de luz &amp;ndash;en mi caso se trata de memorias flash y eeproms, pero la situaci&amp;oacute;n es la misma). La descarga a disco se hace cada cinco segundos, aunque podemos forzar nosotros una mediante la llamada a la funci&amp;oacute;n &lt;i&gt;RegFlushKey()&lt;/i&gt; que, pese a lo que diga la documentaci&amp;oacute;n, hace un volcado de todo lo pendiente, no solo de la &lt;i&gt;Key&lt;/i&gt; abierta.&lt;/p&gt;
&lt;p align="justify"&gt;Pero en disco la cosa no est&amp;aacute; tan clara, y los autores tampoco lo dicen expresamente, pero parece ser que s&amp;iacute;, que el registro se puede fragmentar.&lt;/p&gt;
&lt;p align="justify"&gt;El registro se guarda en disco en bloques de 4KB. Es decir, aunque necesitemos 1 byte, el &lt;i&gt;hive&lt;/i&gt; crecer&amp;aacute; en 4KB. Eso no quiere decir que hayamos desperdiciado el resto, que no va a ocurrir, ya que luego dicho bloque se ir&amp;aacute; rellenando conforme se vayan a&amp;ntilde;adiendo claves.&lt;/p&gt;
&lt;p align="justify"&gt;Ese es el primer nivel de indirecci&amp;oacute;n. Encima existe un nuevo nivel l&amp;oacute;gico, en el que el registro se distribuye en forma de listas sobre dichos bloques, y que realmente conforman la estructura que nosotros vemos. Digamos que este nivel consiste en una especie de mezcla de &amp;aacute;rbol y lista enlazada que se va distribuyendo a lo largo de los bloques en disco.&lt;/p&gt;
&lt;p align="justify"&gt;La combinaci&amp;oacute;n de ambas estructuras permite la fragmentaci&amp;oacute;n de forma muy f&amp;aacute;cil: tan solo hay que ir creando &amp;aacute;rboles y luego eliminando nodos y &amp;aacute;rboles anteriores. De hecho, en poco tiempo podr&amp;iacute;amos tener un buen nivel de fragmentaci&amp;oacute;n, sobre todo cuando hemos instalado y desinstalado un mont&amp;oacute;n de programas.&lt;/p&gt;
&lt;p align="justify"&gt;No obstante, Windows lucha contra esta fragmentaci&amp;oacute;n mediante la compactaci&amp;oacute;n de los espacios libres. Es decir, cuando en un bloque f&amp;iacute;sico hay huecos, estos ser&amp;aacute;n compactados para dejar el mayor espacio libre contiguo, para &amp;ndash;creo entender- volver a ser reutilizado.&lt;/p&gt;
&lt;p align="justify"&gt;No obstante, el bloque no ser&amp;aacute; liberado de disco hasta que no est&amp;eacute; completamente vac&amp;iacute;o, y s&amp;oacute;lo cuando est&amp;eacute; al final del fichero. Es aqu&amp;iacute; donde puede venir la fragmentaci&amp;oacute;n, ya que podr&amp;iacute;amos tener muchos bloques vac&amp;iacute;os por en medio y una jodida clave al final que nos impidiera la limpieza de un buen espacio en disco, ya que el algoritmo de desfragmentaci&amp;oacute;n no coloca los huecos al final, sino que simplemente los maximiza.&lt;/p&gt;
&lt;p align="justify"&gt;Y aqu&amp;iacute; es donde entra la estad&amp;iacute;stica. Estad&amp;iacute;sticamente hablando, siempre habr&amp;aacute; algo de fragmentaci&amp;oacute;n porque habr&amp;aacute; huecos intermedios, que ser&amp;aacute;n rellenados conforme se vayan necesitando, y en el peor de los casos el registro no decrecer&amp;aacute; en tama&amp;ntilde;o, pero tampoco crecer&amp;aacute; hasta que todos los huecos est&amp;eacute;n rellenos.&lt;/p&gt;
&lt;p align="justify"&gt;Lo que m&amp;aacute;s me jode de todo esto es que en el libro no est&amp;aacute; muy claramente contado, sino que el tema de la fragmentaci&amp;oacute;n se recorre de puntillas, como si fuera un pecado. Tan s&amp;oacute;lo se comentan, de pasada, dos funciones que podr&amp;iacute;an permitirnos compactarlo y quiz&amp;aacute;s decrecerlo: &lt;i&gt;RegSaveKey()&lt;/i&gt; y &lt;i&gt;RegReplaceKey()&lt;/i&gt;, que dice son usadas por Windows Backup.&lt;/p&gt;
&lt;p align="justify"&gt;Podr&amp;iacute;amos intentar jugar con dichas funciones para ver si conseguimos compactar nuestro registro pero, si&amp;eacute;ndoos sincero, no tengo ganas de trastear con algo que podr&amp;iacute;a dejar mi ordenador completamente inservible s&amp;oacute;lo por ganar unos cuantos megas de disco&amp;hellip;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=164145" width="1" height="1"&gt;</content><author><name>RFOG</name><uri>http://geeks.ms/members/RFOG/default.aspx</uri></author><category term="Sistemas Operativos" scheme="http://geeks.ms/blogs/rfog/archive/tags/Sistemas+Operativos/default.aspx" /><category term="windows" scheme="http://geeks.ms/blogs/rfog/archive/tags/windows/default.aspx" /><category term="vista" scheme="http://geeks.ms/blogs/rfog/archive/tags/vista/default.aspx" /><category term="libros" scheme="http://geeks.ms/blogs/rfog/archive/tags/libros/default.aspx" /><category term="Win32" scheme="http://geeks.ms/blogs/rfog/archive/tags/Win32/default.aspx" /><category term="Windows 7" scheme="http://geeks.ms/blogs/rfog/archive/tags/Windows+7/default.aspx" /></entry><entry><title>Acronis ya no es lo que era</title><link rel="alternate" type="text/html" href="/blogs/rfog/archive/2010/01/02/acronis-ya-no-es-lo-que-era.aspx" /><id>/blogs/rfog/archive/2010/01/02/acronis-ya-no-es-lo-que-era.aspx</id><published>2010-01-02T11:39:00Z</published><updated>2010-01-02T11:39:00Z</updated><content type="html">&lt;p align="justify"&gt;Vamos a empezar el a&amp;ntilde;o dando ca&amp;ntilde;a de la buena. Acronis siempre ha sido un buen referente en cuanto a copias de seguridad. Recomendado por muchos expertos, yo, sin serlo, nunca hab&amp;iacute;a experimentado problema alguno con el programa. Ni cargaba el sistema, ni produc&amp;iacute;a efectos laterales indeseados y ni siquiera se notaba cuando se estaba realizando la copia de seguridad.&lt;/p&gt;
&lt;p align="justify"&gt;Pero la versi&amp;oacute;n 2010 es otra cosa. Aunque tiene cosas buenas, como que ahora no tarda un cuarto de hora a arrancar analizando las particiones y los discos (y tengo seis). Otra ventaja es que ahora las cosas est&amp;aacute;n mucho m&amp;aacute;s f&amp;aacute;ciles de encontrar. Se nota que han reorganizado la ergonom&amp;iacute;a del programa pensando en el usuario novel y con prisas. Antes encontrar las tareas programadas pod&amp;iacute;a ser una odisea de movimientos por el programa.&lt;/p&gt;
&lt;p align="justify"&gt;No obstante esas mejoras, hay otros aspectos del programa que ciertamente lo hacen, a mi modo de ver, completamente inusable. Y el problema no est&amp;aacute; en los fallos, que los tiene, el problema est&amp;aacute; en la &lt;i&gt;confianza&lt;/i&gt; que te inspira el programa. Hablamos de copias de seguridad, de lo que quiz&amp;aacute;s salve a tu empresa del desastre total. Y si un programa de este tipo no te inspira confianza, lo mejor es que lo quites pese a haberlo pagado a tocateja. Podemos aplicar lo mismo al caso del usuario no profesional. Imagina que pierdes todas las fotos y v&amp;iacute;deos hechos a tu hijo&amp;hellip;&lt;/p&gt;
&lt;p align="justify"&gt;&lt;b&gt;El programa usa el 100% de la CPU&lt;i&gt; &lt;/i&gt;&lt;/b&gt;cuando est&amp;aacute; lanzado. En un Dual Core ser&amp;aacute; el 50%, y el 25% en un Quad. Aunque no est&amp;eacute; haciendo nada. Acronis dispone de un servicio que es el que realmente hace el trabajo duro. El programa que lanzamos no es m&amp;aacute;s que un interfaz hacia dicho servicio, y es ese programa el que consume toda la CPU.&lt;/p&gt;
&lt;p align="justify"&gt;&lt;b&gt;Sigue en memoria una vez cerrado y ya no podemos volverlo a lanzar&lt;/b&gt;. Es decir, cuando lo cierras, deja de usar el 100% de la CPU pero se queda en memoria, menos mal que sin usar tiempo de proceso. Pero a partir de ese momento ya no podremos volver a lanzarlo. Ir&amp;aacute;n cre&amp;aacute;ndose procesos con cada lanzamiento pero no aparecer&amp;aacute; nada en pantalla hasta que no los hayamos matado todos (o reiniciado).&lt;/p&gt;
&lt;p align="justify"&gt;&lt;b&gt;Las copias &lt;i&gt;shadow&lt;/i&gt; interfieren con la &lt;i&gt;shell&lt;/i&gt;&lt;/b&gt;. Acronis 2010 tiene un sistema de copias shadow sobre otra unidad, lo que significa que realiza la misma funcionalidad que el &amp;ldquo;restaurar versiones previas&amp;rdquo; del propio Windows, pero la copia est&amp;aacute; en otra unidad de disco, y as&amp;iacute; matamos dos p&amp;aacute;jaros de un tiro: copia de seguridad y versionado de archivos. El problema est&amp;aacute; en que si tenemos eso activado a veces resulta por completo imposible mover o borrar archivos de la unidad protegida. El explorador se queda indefinidamente esperando algo.&lt;/p&gt;
&lt;p align="justify"&gt;&lt;b&gt;Las copias &lt;i&gt;shadow&lt;/i&gt; se desactivan solas.&lt;/b&gt; S&amp;iacute;, cuando menos te lo esperas, miras el icono de la barra de tareas y resulta que el servicio se ha detenido, sin aviso alguno, y si intentas iniciarlo suele negarse a hacerlo si no abres el Acronis completo. Y entonces a veces empieza desde cero, borrando lo que ya ten&amp;iacute;a y rehaciendo la imagen. Para confiar en &amp;eacute;l.&lt;/p&gt;
&lt;p align="justify"&gt;&lt;b&gt;Problemas varios con el &lt;i&gt;secure zone&lt;/i&gt;. &lt;/b&gt;Cuando activas esta caracter&amp;iacute;stica (que es una partici&amp;oacute;n especial no visible por el sistema en donde se guardar&amp;aacute;n y gestionar&amp;aacute;n de forma autom&amp;aacute;tica las copias de seguridad), aparece una nueva unidad en el Explorador. Si intentamos abrirla nos salta el UAC, y una vez aceptado, podemos ver todas las copias de seguridad que tengamos ah&amp;iacute;, acceder a ellas y recuperar ficheros. Lo que parece sencillo no lo es. En primer lugar es lento de cojones. En segundo no te muestra todas las copias (en concreto las incrementales). Y en tercero muchas veces aparecen como vac&amp;iacute;as.&lt;/p&gt;
&lt;p align="justify"&gt;&lt;b&gt;Montar unidades.&lt;/b&gt; Acronis permite montar ficheros de copia de seguridad como unidades de disco. Cuando funciona, claro, porque la mayor&amp;iacute;a de veces te dice que no encuentra una unidad de disco libre (yo tengo 19), y cuando lo monta tarda como cuarto de hora mientras el ordenador se queda como autista, y a veces tampoco lo consigue.&lt;/p&gt;
&lt;p align="justify"&gt;&lt;b&gt;Ralentiza la carga de Windows entre 20 y 60 segundos&lt;/b&gt; seg&amp;uacute;n c&amp;oacute;mo lo pilles. Mi Windows 7 tarda sobre 40 segundos a arrancar desde que se quita la pantalla del POST de la BIOS hasta que veo el escritorio. Teniendo el Acronis ese tiempo pasa de 40 a 60 u 80, y a veces m&amp;aacute;s.&lt;/p&gt;
&lt;p align="justify"&gt;Si os dais cuenta, pr&amp;aacute;cticamente todas las caracter&amp;iacute;sticas del programa tienen alguna pega, incluso las que funcionaban bien en versiones anteriores. Entiendo que son cosas muy complicadas, sobre todo las novedades, pero es que llevan como diez revisiones de la versi&amp;oacute;n 2010 y no dan pie con bola. Se escudan en los cambios que Microsoft ha hecho al n&amp;uacute;cleo y a los servicios de Windows, pero a mi modo de ver eso no es m&amp;aacute;s que una excusa para no solucionar los problemas, ya sea porque no quieran o porque no puedan. &lt;/p&gt;
&lt;p align="justify"&gt;Son todas las cosas que me est&amp;aacute;n ocurriendo a mi en mi Windows 7 x64 con 8GB de RAM en un Q4 con 6 discos duros. Si os vais a los foros de Acronis en la web del fabricante ver&amp;eacute;is c&amp;oacute;mo son miles las personas que est&amp;aacute;n teniendo problemas similares.&lt;/p&gt;
&lt;p align="justify"&gt;Esto me lleva a pensar en una idea aprovechando las caracter&amp;iacute;sticas de Windows Vista y 7: utilizar las copias &lt;i&gt;shadow&lt;/i&gt; para hacer una copia. El algoritmo ser&amp;iacute;a el siguiente:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;div align="justify"&gt;Crear una copia shadow.&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;div align="justify"&gt;Montarla en una carpeta o unidad.&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;div align="justify"&gt;Copiar dicha unidad en otro disco, quiz&amp;aacute;s zipe&amp;aacute;ndola o de cualquier otra forma.&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;div align="justify"&gt;Desmontar la copia.&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;div align="justify"&gt;Opcionalmente borrarla.&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p align="justify"&gt;Tan solo tendr&amp;iacute;amos que programar una tarea con un script de comandos con dichas instrucciones y listo, se podr&amp;iacute;a copiar peri&amp;oacute;dicamente. Incluso podr&amp;iacute;amos tener una especie de &lt;i&gt;shadow&lt;/i&gt; en destino, haciendo una copia en una carpeta diferente cada d&amp;iacute;a de la semana.&lt;/p&gt;
&lt;p align="justify"&gt;Yo tengo algo parecido ahora mismo, pero simplemente se trata de un xcopy sobre las carpetas normales, con lo que los ficheros abiertos no se copian. Y son los abiertos los que interesa copiar, ya que son los que han variado.&lt;/p&gt;
&lt;p align="justify"&gt;Siendo un poco cucos y usando el atributo de archivo (que se pone cada vez que un fichero ha sido modificado) podr&amp;iacute;amos tener un hist&amp;oacute;rico semanal o quincenal o mensual. &lt;/p&gt;
&lt;p align="justify"&gt;Imaginemos que tenemos la unidad Z:, que es donde est&amp;aacute;n nuestros datos. Hacemos una copia shadow y la montamos en, por ejemplo Z:\Shadow. Hacemos la copia de dicha carpeta sobre nuestra unidad de copia de seguridad, digamos M:\Backups\&amp;lt;dia_de_la_semana&amp;gt;. Y copiamos s&amp;oacute;lo los archivos con el atributo de archivo activado, con lo que en M:\Backups\&amp;lt;dia_de_la_semana&amp;gt; tendremos los cambios de ese d&amp;iacute;a. Si generamos un registro de los ficheros copiados, y queremos recuperar la &amp;uacute;ltima versi&amp;oacute;n de uno de ellos, abrimos dicho log y buscamos la &amp;uacute;ltima ocurrencia del mismo. Si hemos decidido tener un hist&amp;oacute;rico semanal, cada domingo hacemos una copia completa. O incluso podemos tener una &lt;i&gt;cola de copias de seguridad&lt;/i&gt;. Si estamos a jueves, el mi&amp;eacute;rcoles ser&amp;aacute; la copia anterior, y as&amp;iacute; hacia atr&amp;aacute;s hasta el viernes. Evidentemente podemos elegir la periodicidad que queramos siempre que tengamos sitio en la unidad.&lt;/p&gt;
&lt;p align="justify"&gt;&lt;b&gt;El problema es que no s&amp;eacute; c&amp;oacute;mo hacerlo&lt;/b&gt;. He estado mirando varios comandos pero no he conseguido sacarle punta, y si Windows lo hace autom&amp;aacute;ticamente, tambi&amp;eacute;n podr&amp;aacute; hacerse a mano. Es cuesti&amp;oacute;n de investigar m&amp;aacute;s a fondo, y yo no tengo tiempo. Lo dejo abierto para quien quiera hacerlo, y si me lo env&amp;iacute;a se lo publicar&amp;eacute; aqu&amp;iacute;.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=164094" width="1" height="1"&gt;</content><author><name>RFOG</name><uri>http://geeks.ms/members/RFOG/default.aspx</uri></author><category term="escariotrop&amp;#237;as gimn&amp;#233;sicas" scheme="http://geeks.ms/blogs/rfog/archive/tags/escariotrop_26002300_237_3B00_as+gimn_26002300_233_3B00_sicas/default.aspx" /><category term="windows" scheme="http://geeks.ms/blogs/rfog/archive/tags/windows/default.aspx" /><category term="chapuzas" scheme="http://geeks.ms/blogs/rfog/archive/tags/chapuzas/default.aspx" /><category term="bugs" scheme="http://geeks.ms/blogs/rfog/archive/tags/bugs/default.aspx" /><category term="vista" scheme="http://geeks.ms/blogs/rfog/archive/tags/vista/default.aspx" /><category term="Windows 7" scheme="http://geeks.ms/blogs/rfog/archive/tags/Windows+7/default.aspx" /></entry><entry><title>BingOS o cómo no reventar de impaciencia</title><link rel="alternate" type="text/html" href="/blogs/rfog/archive/2009/12/28/bingos-o-c-243-mo-no-reventar-de-impaciencia.aspx" /><id>/blogs/rfog/archive/2009/12/28/bingos-o-c-243-mo-no-reventar-de-impaciencia.aspx</id><published>2009-12-28T11:01:13Z</published><updated>2009-12-28T11:01:13Z</updated><content type="html">&lt;p&gt;Ya es oficial. Ya no tengo que morderme los nudillos, ni ponerme esparadrapos en la boca, ni pisarme a mi mismo para evitar soltarlo: Microsoft ha lanzado un nuevo sistema operativo especialmente diseñado para los ultraligeros y toda su familia anexa, por lo que tampoco descarto ver lectores de libros-e con esta tecnología en sus tripas.&lt;/p&gt;  &lt;p&gt;Como está basado en Windows CE, el núcleo será igual de estable, y al ser una versión “destripada”, todavía más. Por ejemplo, yo una vez conseguí una imagen de CE de 4MB conteniendo la GUI completa (también IE) e ignorando muchas cosas accesorias.&lt;/p&gt;  &lt;p&gt;La ventaja evidente es que muchos de los programas existentes para CE (léase Windows Mobile) funcionarán sin modificar…&lt;/p&gt;  &lt;p&gt;Pero la cosa no termina ahí, sino que, como nos tiene habituados, MS sacará varias versiones, incluso una “Starter” que sólo podrá navegar por determinados sitios, así como otra con sólo la posibilidad de navegación.&lt;/p&gt;  &lt;p&gt;Parece ser que la idea es darle una buena coz a Google, y aunque MS sea un dinosaurio lento y torpón, si se decide a poner en marcha la máquina, saca ventaja a quien sea. El anuncio más o menos oficial, aquí: &lt;a href="http://www.ethek.com/bingos-el-nuevo-sistema-operativo-de-microsoft/"&gt;http://www.ethek.com/bingos-el-nuevo-sistema-operativo-de-microsoft/&lt;/a&gt;.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=163751" width="1" height="1"&gt;</content><author><name>RFOG</name><uri>http://geeks.ms/members/RFOG/default.aspx</uri></author><category term="escariotrop&amp;#237;as gimn&amp;#233;sicas" scheme="http://geeks.ms/blogs/rfog/archive/tags/escariotrop_26002300_237_3B00_as+gimn_26002300_233_3B00_sicas/default.aspx" /><category term="UMPC" scheme="http://geeks.ms/blogs/rfog/archive/tags/UMPC/default.aspx" /><category term="Windows CE" scheme="http://geeks.ms/blogs/rfog/archive/tags/Windows+CE/default.aspx" /><category term="hardware" scheme="http://geeks.ms/blogs/rfog/archive/tags/hardware/default.aspx" /><category term="Win32" scheme="http://geeks.ms/blogs/rfog/archive/tags/Win32/default.aspx" /></entry><entry><title>Concurso “NET Minds”</title><link rel="alternate" type="text/html" href="/blogs/rfog/archive/2009/12/07/concurso-net-minds.aspx" /><id>/blogs/rfog/archive/2009/12/07/concurso-net-minds.aspx</id><published>2009-12-07T11:49:00Z</published><updated>2009-12-07T11:49:00Z</updated><content type="html">&lt;p&gt;A veces a uno lo sorprenden (y cuando digo sorprenden es sorprenden). Y encima gratamente. Primero la imagen que os llevar&amp;aacute; a la web:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://msdn.microsoft.com/es-es/net_minds.aspx"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a target="_blank" href="http://msdn.microsoft.com/es-es/net_minds.aspx"&gt;&lt;img height="507" width="610" src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rfog/image_5F00_4DCE8AF3.png" alt="image" border="0" title="image" style="border-bottom:0px;border-left:0px;display:inline;border-top:0px;border-right:0px;" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;Se trata de un juego en el que los tres primeros en terminarlo tendr&amp;aacute;n un Visual Studio 2010 con suscripci&amp;oacute;n a la MSDN Premium, todo ello valorado en muuuuuuuuuuuuuuuucha pasta gansa.&lt;/p&gt;
&lt;p&gt;Como podr&amp;eacute;is comprender, yo no voy a participar porque si no ser&amp;iacute;a el seguro ganador de no una, sino de las tres suscripciones.[tachado]&lt;/p&gt;
&lt;p&gt;No se trata de un concurso de sapiencia sobre desarrollo (y si lo fuera volver&amp;iacute;a a ganar[tachado]), sino un concurso de inteligencia del estilo de &lt;/p&gt;
&lt;p&gt;&lt;i&gt;En el armario de un jefe de proyecto nos encontramos que todos los polos son blancos menos dos, todos son azules menos dos y todos son rosas menos dos.&lt;/i&gt;&lt;/p&gt;
&lt;p&gt;&lt;i&gt;&amp;iquest;Cu&amp;aacute;ntos polos hay de cada color?&lt;/i&gt;&lt;/p&gt;
&lt;p&gt;Por eso cualquiera puede participar, no ten&amp;eacute;is que ser ni genios de la programaci&amp;oacute;n (como yo[tachado]) sino genios &lt;i&gt;a pelo&lt;/i&gt; (tambi&amp;eacute;n como yo[tachado]).&lt;/p&gt;
&lt;p&gt;PS: S&amp;iacute;, ya s&amp;eacute;, se me olvid&amp;oacute; tomar las pastillas de humildad y modestia, y pero es que no tengo abuela y estoy de co&amp;ntilde;a. No vaya nadie a mosque&amp;aacute;rseme por un qu&amp;iacute;tame all&amp;aacute; esas pajas (mentales, digo, no de las otras).&lt;/p&gt;
&lt;p&gt;NOTA: Las partes entre par&amp;eacute;ntesis en las que pongo mis tonter&amp;iacute;as, y el p&amp;aacute;rrafo que empieza por &amp;quot;Como pod&amp;eacute;is comprender&amp;quot; los he escrito tachados, pero en la visualizaci&amp;oacute;n no aparecen como tal. Cosas de los BUGS.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=162087" width="1" height="1"&gt;</content><author><name>RFOG</name><uri>http://geeks.ms/members/RFOG/default.aspx</uri></author><category term="escariotrop&amp;#237;as gimn&amp;#233;sicas" scheme="http://geeks.ms/blogs/rfog/archive/tags/escariotrop_26002300_237_3B00_as+gimn_26002300_233_3B00_sicas/default.aspx" /><category term="licencias" scheme="http://geeks.ms/blogs/rfog/archive/tags/licencias/default.aspx" /><category term="Visual Studio" scheme="http://geeks.ms/blogs/rfog/archive/tags/Visual+Studio/default.aspx" /></entry><entry><title>Salió QT 4.6</title><link rel="alternate" type="text/html" href="/blogs/rfog/archive/2009/12/04/sali-243-qt-4-6.aspx" /><id>/blogs/rfog/archive/2009/12/04/sali-243-qt-4-6.aspx</id><published>2009-12-04T14:53:00Z</published><updated>2009-12-04T14:53:00Z</updated><content type="html">&lt;p&gt;Pues eso, que ha salido hace nada la versión 4.6 de QT, con importantes añadidos como el soporte para dispositivos táctiles multitouch, grandes aceleraciones en el renderizado gráfico y soporte para Symbian, o eso es lo que dice, entre otras cosas, la noticia de la salida del mismo. Podemos obtenerlo desde aquí: &lt;a title="http://qt.nokia.com/" href="http://qt.nokia.com/"&gt;http://qt.nokia.com/&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;Si no queremos soporte para Visual C++, con instalar el paquete está todo listo para funcionar. No obstante, dado que el compilador de Visual C++ es significativamente mejor que el de GNU, es recomendable instalarse el AddOn para Visual Sutdio y compilarse una versión para él.&lt;/p&gt;  &lt;p&gt;&lt;b&gt;&lt;u&gt;Compilar QT para Visual C++       &lt;br /&gt;&lt;/u&gt;&lt;/b&gt;Ya lo expliqué &lt;a href="http://geeks.ms/blogs/rfog/archive/2009/08/31/instalar-qt-en-visual-studio.aspx"&gt;aquí&lt;/a&gt;, y parece ser que esta versión tiene el mismo bug a la hora de compilarnos la versión para Visual C++, por lo que hay que seguir los pasos descritos allí. De todos modos, voy a ampliar algo la información.&lt;/p&gt;  &lt;p&gt;QT se instala por defecto en C:\QT\&amp;lt;versión&amp;gt;, y yo voy a asumir que lo has hecho así. En mi caso tengo un fichero BAT con el siguiente contenido:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;cd %1\qt     &lt;br /&gt;configure -debug-and-release -shared -no-qt3support –opensource      &lt;br /&gt;nmake      &lt;br /&gt;del src\3rdparty\webkit\WebCore\tmp\moc\release_shared\mocinclude.tmp       &lt;br /&gt;del src\3rdparty\webkit\WebCore\tmp\moc\debug_shared\mocinclude.tmp       &lt;br /&gt;copy src\3rdparty\webkit\WebCore\tmp\moc\release_shared\moc_QnetworkReplyHandler.cpp src\3rdparty\webkit\WebCore\tmp\moc\debug_shared\       &lt;br /&gt;nmake       &lt;br /&gt;cd ..       &lt;br /&gt;cd ..&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Tan sólo hay que posicionarse en una consola de comandos en la carpeta de C:\QT y ejecutar el comando configure &amp;lt;ruta&amp;gt;, picar “y” cuando se nos pregunte y esperar las varias horas que tarda a compilarse el tema.&lt;/p&gt;  &lt;p&gt;&lt;b&gt;&lt;u&gt;La consola       &lt;br /&gt;&lt;/u&gt;&lt;/b&gt;Tenemos que abrir una consola de compilación, que trae listo un entorno de compilación para Visual C++. Si tenemos instalado el SDK, la consola está en su carpeta en el Menú Inicio, y si no usaremos la de Visual C++.&lt;/p&gt;  &lt;p&gt;Una vez abierta tenemos que elegir el entorno deseado con el comando “setenv”, que reflejamos en la captura:&lt;/p&gt;  &lt;p&gt;&lt;img style="border-bottom:0px;border-left:0px;display:inline;border-top:0px;border-right:0px;" title="image" border="0" alt="image" src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rfog/image_5F00_540A21A3.png" width="610" height="305" /&gt; &lt;/p&gt;  &lt;p&gt;Debemos elegir entre “/Debug” o “/Release”, entre “/x86”, “/x64” o “/ia64”. También entre “/xp”, “/vista”, “/2003”, “/2008” o “/win7” como sistema operativo base. Hasta donde yo sé, esta última opción no afecta para nada al resultado de la compilación de QT, por lo que con poner “/xp” nos basta. Las otras sí que afectan, construyéndonos QT alrededor de un runtime de depuración o final, o un QT de 32 ó 64 bits. La opción “/ia64” no sé si generará algo útil o no.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=161859" width="1" height="1"&gt;</content><author><name>RFOG</name><uri>http://geeks.ms/members/RFOG/default.aspx</uri></author><category term="c++" scheme="http://geeks.ms/blogs/rfog/archive/tags/c_2B002B00_/default.aspx" /><category term="Visual Studio" scheme="http://geeks.ms/blogs/rfog/archive/tags/Visual+Studio/default.aspx" /><category term="lenguajes" scheme="http://geeks.ms/blogs/rfog/archive/tags/lenguajes/default.aspx" /><category term="QT" scheme="http://geeks.ms/blogs/rfog/archive/tags/QT/default.aspx" /></entry><entry><title>Obtener tu propia versión</title><link rel="alternate" type="text/html" href="/blogs/rfog/archive/2009/12/03/obtener-tu-propia-versi-243-n.aspx" /><id>/blogs/rfog/archive/2009/12/03/obtener-tu-propia-versi-243-n.aspx</id><published>2009-12-03T10:22:10Z</published><updated>2009-12-03T10:22:10Z</updated><content type="html">&lt;p&gt;Muchos habréis observado que en las propiedades de un ejecutable o una DLL suelen aparecer, en la pestaña Detalles de las propiedades, una serie de nombres y de datos sobre la versión de dicho fichero.&lt;/p&gt;  &lt;p&gt;Eso se consigue embebiendo en el ejecutable un recurso de versión, que en Win32 se llama RCVERSION y que consta de una serie de cadenas y valores predefinidos que podemos rellenar a nuestro gusto.&lt;/p&gt;  &lt;p&gt;En las imágenes de abajo podemos ver un ejemplo añadido a un ejecutable, tanto desde C++ Builder como desde Visual C++.&lt;/p&gt;  &lt;p&gt;&lt;img style="border-bottom:0px;border-left:0px;display:inline;border-top:0px;border-right:0px;" title="image" border="0" alt="image" src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rfog/image_5F00_26D238F3.png" width="610" height="456" /&gt;&lt;/p&gt;  &lt;p&gt;&lt;img style="border-bottom:0px;border-left:0px;display:inline;border-top:0px;border-right:0px;" title="image" border="0" alt="image" src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rfog/image_5F00_042DFA78.png" width="511" height="535" /&gt;&amp;#160; &lt;/p&gt;  &lt;p&gt;Si os fijáis, ambas tienen más o menos los mismos elementos, pero en el caso del C++Builder existe la opción de incrementar el número de Build automáticamente. Hasta donde yo sé, eso no lo permite Visual C++ (quizás se haga en conjunción con un CVS o cuando haya uno compatible), y básicamente consiste en incrementar automáticamente el último numerito cada vez que compilemos algo. A lo largo de diferentes versiones del producto, este incremento se producía cuando se hacía un Build, un Make o incluso nunca (debido a un bug). En la versión 2010 se hace cada vez que compilemos algo.&lt;/p&gt;  &lt;p&gt;Bueno, una vez que hemos especificado nuestro recurso de versión, es tiempo de que podamos leerlo desde el propio ejecutable para poderlo poner, por ejemplo, en la pantalla de “Acerca”, en la de “Splash” o donde queramos. Si os dais cuenta, esos números suelen aparecer en muchas aplicaciones.&lt;/p&gt;  &lt;p&gt;El código es muy sencillo:&lt;/p&gt;  &lt;pre&gt;DWORD handle;
DWORD size = GetFileVersionInfoSize(Application-&amp;gt;ExeName.w_str(), &amp;amp;handle);
wchar_t *buffer = new wchar_t[size + 1];
GetFileVersionInfo(Application-&amp;gt;ExeName.w_str(), 0, size, buffer);
VS_FIXEDFILEINFO *pFixedInfo;
UINT uVersionLen;
if (VerQueryValue(buffer, L&amp;quot;\\&amp;quot;, (void**) &amp;amp; pFixedInfo, (UINT*) &amp;amp; uVersionLen) != 0)
{
    String version = L&amp;quot; &amp;quot; + String(HIWORD(pFixedInfo-&amp;gt;dwFileVersionMS)) + L&amp;quot;.&amp;quot; + String(LOWORD(pFixedInfo-&amp;gt;dwFileVersionMS)) + L&amp;quot;.&amp;quot; + String
    (HIWORD(pFixedInfo-&amp;gt;dwFileVersionLS)) + L&amp;quot;.&amp;quot; + String(LOWORD(pFixedInfo-&amp;gt;dwFileVersionLS));
    m_caption = Caption + version + L&amp;quot; - &amp;quot;;
    Caption = m_caption + m_document-&amp;gt;FileName;
}
delete[] buffer;&lt;/pre&gt;

&lt;p&gt;El ejemplo que he puesto es para C++ Builder Unicode, pero resulta trivial convertirlo a C ó C++ estándar. Tan sólo hay que cambiar el tipo de las cadenas por las adecuadas.&lt;/p&gt;

&lt;p&gt;Primero se hace una llamada a &lt;i&gt;GetFileVersionInfoSize()&lt;/i&gt; pasando la ruta de nuestro ejecutable y un DWORD que de nada sirve. Con el tamaño del recurso, llamamos a &lt;i&gt;GetFileVersionInfo()&lt;/i&gt; volviendo a pasar la ruta del ejecutable y un buffer con el tamaño adecuado.&lt;/p&gt;

&lt;p&gt;Después creamos un puntero a una estructura del tipo &lt;i&gt;VS_FIXEDFILEINFO&lt;/i&gt; y la pasamos a la función &lt;i&gt;VerQueryValue()&lt;/i&gt;, que también recibe el buffer original, qué parte del recurso queremos sacar (“\\”, es decir, la versión raíz –los recursos de versión se pueden embeber unos dentro de otros) y algún que otro valor más.&lt;/p&gt;

&lt;p&gt;Si esta función encuentra lo que le decimos, entonces podemos usar el puntero de la estructura y formatear una cadena con los cuatro números de versión.&lt;/p&gt;

&lt;p&gt;Lo que hagamos con esa cadena es cosa nuestra. En este caso la añadimos al título de la ventana actual y lo guardamos en una variable miembro que usaremos cada vez que cambiemos de documento.&lt;/p&gt;

&lt;p&gt;Y no nos olvidemos de liberar la cadena asignada.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=161847" width="1" height="1"&gt;</content><author><name>RFOG</name><uri>http://geeks.ms/members/RFOG/default.aspx</uri></author><category term="c++" scheme="http://geeks.ms/blogs/rfog/archive/tags/c_2B002B00_/default.aspx" /><category term="Win32" scheme="http://geeks.ms/blogs/rfog/archive/tags/Win32/default.aspx" /><category term="C++ Builder" scheme="http://geeks.ms/blogs/rfog/archive/tags/C_2B002B00_+Builder/default.aspx" /></entry><entry><title>Manifiesto en defensa de los derechos fundamentales en internet</title><link rel="alternate" type="text/html" href="/blogs/rfog/archive/2009/12/02/manifiesto-en-defensa-de-los-derechos-fundamentales-en-internet.aspx" /><id>/blogs/rfog/archive/2009/12/02/manifiesto-en-defensa-de-los-derechos-fundamentales-en-internet.aspx</id><published>2009-12-02T10:06:38Z</published><updated>2009-12-02T10:06:38Z</updated><content type="html">&lt;p&gt;Origen: &lt;a title="http://fernand0.blogalia.com/historias/65244" href="http://fernand0.blogalia.com/historias/65244"&gt;http://fernand0.blogalia.com/historias/65244&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Ante la inclusión en el Anteproyecto de Ley de Economía sostenible de modificaciones legislativas que afectan al libre ejercicio de las libertades de expresión, información y el derecho de acceso a la cultura a través de Internet, los periodistas, bloggers, usuarios, profesionales y creadores de internet manifestamos nuestra firme oposición al proyecto, y declaramos que...    &lt;br /&gt;1.- Los derechos de autor no pueden situarse por encima de los derechos fundamentales de los ciudadanos, como el derecho a la privacidad, a la seguridad, a la presunción de inocencia, a la tutela judicial efectiva y a la libertad de expresión.     &lt;br /&gt;2.- La suspensión de derechos fundamentales es y debe seguir siendo competencia exclusiva del poder judicial. Ni un cierre sin sentencia. Este anteproyecto, en contra de lo establecido en el artículo 20.5 de la Constitución, pone en manos de un órgano no judicial -un organismo dependiente del ministerio de Cultura-, la potestad de impedir a los ciudadanos españoles el acceso a cualquier página web.     &lt;br /&gt;3.- La nueva legislación creará inseguridad jurídica en todo el sector tecnológico español, perjudicando uno de los pocos campos de desarrollo y futuro de nuestra economía, entorpeciendo la creación de empresas, introduciendo trabas a la libre competencia y ralentizando su proyección internacional.     &lt;br /&gt;4.- La nueva legislación propuesta amenaza a los nuevos creadores y entorpece la creación cultural. Con Internet y los sucesivos avances tecnológicos se ha democratizado extraordinariamente la creación y emisión de contenidos de todo tipo, que ya no provienen prevalentemente de las industrias culturales tradicionales, sino de multitud de fuentes diferentes.     &lt;br /&gt;5.- Los autores, como todos los trabajadores, tienen derecho a vivir de su trabajo con nuevas ideas creativas, modelos de negocio y actividades asociadas a sus creaciones. Intentar sostener con cambios legislativos a una industria obsoleta que no sabe adaptarse a este nuevo entorno no es ni justo ni realista. Si su modelo de negocio se basaba en el control de las copias de las obras y en Internet no es posible sin vulnerar derechos fundamentales, deberían buscar otro modelo.     &lt;br /&gt;6.- Consideramos que las industrias culturales necesitan para sobrevivir alternativas modernas, eficaces, creíbles y asequibles y que se adecuen a los nuevos usos sociales, en lugar de limitaciones tan desproporcionadas como ineficaces para el fin que dicen perseguir.     &lt;br /&gt;7.- Internet debe funcionar de forma libre y sin interferencias políticas auspiciadas por sectores que pretenden perpetuar obsoletos modelos de negocio e imposibilitar que el saber humano siga siendo libre.     &lt;br /&gt;8.- Exigimos que el Gobierno garantice por ley la neutralidad de la Red en España, ante cualquier presión que pueda producirse, como marco para el desarrollo de una economía sostenible y realista de cara al futuro.     &lt;br /&gt;9.- Proponemos una verdadera reforma del derecho de propiedad intelectual orientada a su fin: devolver a la sociedad el conocimiento, promover el dominio público y limitar los abusos de las entidades gestoras.     &lt;br /&gt;10.- En democracia las leyes y sus modificaciones deben aprobarse tras el oportuno debate público y habiendo consultado previamente a todas las partes implicadas. No es de recibo que se realicen cambios legislativos que afectan a derechos fundamentales en una ley no orgánica y que versa sobre otra materia.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=161720" width="1" height="1"&gt;</content><author><name>RFOG</name><uri>http://geeks.ms/members/RFOG/default.aspx</uri></author></entry><entry><title>Cómo se accede al hardware</title><link rel="alternate" type="text/html" href="/blogs/rfog/archive/2009/11/23/c-243-mo-se-accede-al-hardware.aspx" /><id>/blogs/rfog/archive/2009/11/23/c-243-mo-se-accede-al-hardware.aspx</id><published>2009-11-23T18:20:00Z</published><updated>2009-11-23T18:20:00Z</updated><content type="html">&lt;p align="justify"&gt;Dado el &amp;eacute;xito que est&amp;aacute;n teniendo estas entradas, voy a dar otra vuelta de tuerca al tema y voy a explicar c&amp;oacute;mo un programador puede trastear con el hardware, cosa que al final, todos los micros terminan haciendo. No voy a hablar de Windows, ni de ning&amp;uacute;n otro sistema operativo, sino que voy a intentar explicar c&amp;oacute;mo, a trav&amp;eacute;s del c&amp;oacute;digo, se accede al hardware, perif&amp;eacute;ricos y dem&amp;aacute;s. Esta entrada es completamente te&amp;oacute;rica y no me voy a centrar en ning&amp;uacute;n micro ni hardware en concreto, ya que no vale la pena dada la amplia variedad disponible y que, adem&amp;aacute;s, esto no se puede hacer desde Windows (ni desde cualquier otro PC si no arrancamos con algo como MS-DOS y a veces ni siquiera as&amp;iacute;).&lt;/p&gt;
&lt;p align="justify"&gt;Todos sab&amp;eacute;is (o deber&amp;iacute;ais) que un microprocesador consta de varios subconjuntos l&amp;oacute;gicos: la ALU, que hace c&amp;aacute;lculos aritm&amp;eacute;ticos, los registros de prop&amp;oacute;sito general, que son unas celdillas de memoria interna al micro para usos varios, la unidad de decodificaci&amp;oacute;n y ejecuci&amp;oacute;n, que se encarga de interpretar la instrucci&amp;oacute;n cargada, y en micros m&amp;aacute;s modernos podemos encontrarnos con m&amp;oacute;dulos convertidores anal&amp;oacute;gico-digitales, unidades de coma flotante, unidades SIMD, etc.&lt;/p&gt;
&lt;p align="justify"&gt;La arquitectura de los microcontroladores es algo diferente a la de los microprocesadores, muchas veces s&amp;oacute;lo en apariencia, aunque en general programar un microcontrolador es m&amp;aacute;s f&amp;aacute;cil porque normalmente s&amp;oacute;lo hay que ir activando bloques y funcionan sin m&amp;aacute;s. Es decir, si queremos un timer, o un AD, o una UART (puerto serie, para entendernos), simplemente se activan y configuran con las instrucciones adecuadas y listo. En un microprocesador suele ser m&amp;aacute;s complicado, ya que hay de por medio otros temas, como prioridades entre los dispositivos y dem&amp;aacute;s.&lt;/p&gt;
&lt;p align="justify"&gt;Por otro lado, cuando en inform&amp;aacute;tica se habla de unos y ceros, se est&amp;aacute; haciendo una importante abstracci&amp;oacute;n l&amp;oacute;gica. En general, a nivel de se&amp;ntilde;ales el&amp;eacute;ctricas, lo que se entiende por un uno podr&amp;iacute;a ser que una pata del micro est&amp;eacute; a 5V, pero no siempre es as&amp;iacute;, porque si es una arquitectura basada en l&amp;oacute;gica negativa, un uno ser&amp;aacute; cuando dicha pata est&amp;eacute; a 0V y un cero cuando valga 5V. Es decir, dependiendo de la &lt;i&gt;l&amp;oacute;gica&lt;/i&gt;, un uno ser&amp;aacute; una cosa u otra. De hecho, conforme vamos avanzando en velocidades, un uno ni siquiera es un nivel, sino un &lt;i&gt;flanco&lt;/i&gt;. En otras palabras, cuando nosotros leemos una pata de un micro a 1 lo que hemos le&amp;iacute;do es el paso de la misma de 0 a n voltios, o al rev&amp;eacute;s. De hecho, nunca debemos asumir que, si leemos algo y est&amp;aacute; a 1, la pata equivalente vaya a estarlo tambi&amp;eacute;n. Depender&amp;aacute; de muchas cosas y siempre tendremos que morir en la documentaci&amp;oacute;n t&amp;eacute;cnica del micro, de la placa o de quien quiera que haya hecho nuestro hardware.&lt;/p&gt;
&lt;p align="justify"&gt;Y con esto hemos dado un paso m&amp;aacute;s: podemos leer el nivel (o mejor dicho, el estado) de una pata. Es decir, dentro de nuestro micro hay algo que cuando nosotros ejecutamos una instrucci&amp;oacute;n en ensamblador, nos devuelve un 0 o un 1 dependiendo de lo que haya ocurrido en una de sus patas. En general, y dependiendo del tipo de micro, las patas vienen agrupadas en bloques de 8 o 16, que es lo que se conoce como un &lt;i&gt;puerto&lt;/i&gt;, y una lectura sobre &amp;eacute;l nos devolver&amp;aacute; un byte o un word con el equivalente l&amp;oacute;gico.&lt;/p&gt;
&lt;p align="justify"&gt;En los microcontroladores es habitual que el espacio de direcciones se encuentre separado por tipos. Tendremos un espacio de direcciones para el c&amp;oacute;digo, otro para la RAM (ya sea interna o externa), otro para los puertos que acabamos de ver, para EEPROM interna si tenemos, etc. O visto de otra forma: no nos vale con decir que queremos leer de la direcci&amp;oacute;n de memoria 0x12345678, sino que tenemos que indicar tambi&amp;eacute;n de qu&amp;eacute; tipo es. En general, esto se consigue con el tipo de instrucci&amp;oacute;n ensamblador, que es diferente para cada uno.&lt;/p&gt;
&lt;p align="justify"&gt;No obstante, a veces los espacios est&amp;aacute;n mezclados, o solo tenemos uno, o dependiendo del rango de direcci&amp;oacute;n estaremos actuando sobre la RAM, la ROM o lo que sea. Todo ello depende del micro y c&amp;oacute;mo se configure, y os puedo asegurar que cada fabricante lo hace de una forma, no s&amp;oacute;lo para los suyos, sino incluso para cada familia o grupo.&lt;/p&gt;
&lt;p align="justify"&gt;Si esos elementos est&amp;aacute;n dentro del micro, lo tenemos f&amp;aacute;cil, ya que con muy pocas instrucciones (y a veces ninguna), &amp;eacute;ste est&amp;aacute; listo para funcionar. Hay micros que tienen RAM, EEPROM, ROM, IO, todo ello dentro de s&amp;iacute; mismo, pero hay otros en los que algunos de estos elementos est&amp;aacute;n (o pueden estar) fuera, en circuitos independientes.&lt;/p&gt;
&lt;p align="justify"&gt;Es entonces cuando entran en juego el chip select, que son unas patas extra que sirven para alertar al dispositivo adecuado. Supongamos por un momento que nuestra arquitectura tiene todos los elementos externos y que vamos a configurarlos de la siguiente manera: de la direcci&amp;oacute;n de memoria 0 a la 0x7fff, est&amp;aacute; la ROM en el chip select 0. De la 0x8000 a la 0x8fff tenemos la EEPROM, y de la 0x9000 a la 0xafff la RAM. Lo primero es conectar esos rangos del bus de direcciones con cada chip equivalente. Por ejemplo, para la ROM podemos dejarnos sin conectar la pata 15 del bus de direcciones porque no va a ser usada nunca, ahorrando complejidad en las pistas.&lt;/p&gt;
&lt;p align="justify"&gt;Luego tenemos que cablear los chip select, que en nuestro caso son dos patas extra del micro. Cuando en ellas haya un 00, estaremos accediendo a la ROM, cuando haya un 01 a la RAM, y cuando haya un 10 a la EEPROM. Si nos damos cuenta nos queda la combinaci&amp;oacute;n 11, que podr&amp;iacute;amos asignar a perif&amp;eacute;ricos o dejar sin usar. Tenemos que poner combinaciones de puertas l&amp;oacute;gicas de tal forma que cada una de esas combinaciones activen el o los chips correspondientes.&lt;/p&gt;
&lt;p align="justify"&gt;&amp;iquest;C&amp;oacute;mo? Pues con l&amp;oacute;gica combinatoria, puertas AND, NAND, NOR, XNOR, etc. No hay una &amp;uacute;nica soluci&amp;oacute;n, y cuando las placas son algo complejas se suele usar una FPGA o similar, que debe ser programada para esto y para m&amp;aacute;s cosas. Recordemos que quiz&amp;aacute;s un chip est&amp;eacute; activo cuando su pata CS est&amp;eacute; a cero, y si se tratara de los chips donde est&amp;aacute; la ROM, tendr&amp;iacute;amos que primero negar los dos CS que salen del micro y luego poner una NAND entre ellos (y da la casualidad que hay un chip con esa configuraci&amp;oacute;n exacta).&lt;/p&gt;
&lt;p align="justify"&gt;Ahora que ya tenemos el hardware, nos hace falta el software. Lo primero es decirle al micro qu&amp;eacute; CS se corresponde a qu&amp;eacute; &amp;aacute;rea de memoria, de forma que cuando escribamos dentro de un rango, se active autom&amp;aacute;ticamente la combinaci&amp;oacute;n de CS elegida.&lt;/p&gt;
&lt;p align="justify"&gt;No lo he dicho, pero un micro tiene un bus de direcciones y un bus de datos. En el bus de direcciones se pone la direcci&amp;oacute;n a acceder, y en el de datos o bien obtenemos el dato que haya en esa direcci&amp;oacute;n o bien lo ponemos nosotros para que sea le&amp;iacute;do por el elemento externo. En el caso que estamos viendo, se trata de un micro de 8 bits, que tendr&amp;aacute; un bus de 16 bits (generalmente 16 patillas dedicadas a ello, aunque a veces no son tantas y entonces hay que hacer &amp;ldquo;trucos&amp;rdquo; que no voy a explicar aqu&amp;iacute;) y otro de 8 para los datos. Volviendo a los p&amp;aacute;rrafos anteriores, tanto el bus de datos como el de direcciones est&amp;aacute; conectado a todos los chips externos que los necesiten (ya hemos visto que, por ejemplo, el bit de mayor peso del de direcciones no es necesario para la ROM y por tanto no es necesario cablearlo). Con el CS correspondiente, tan s&amp;oacute;lo se activar&amp;aacute; el chip correspondiente, que atender&amp;aacute; la petici&amp;oacute;n.&lt;/p&gt;
&lt;p align="justify"&gt;Ahora necesitamos una pata extra, la WR, para indicar al perif&amp;eacute;rico si queremos leer o escribir. Esto tambi&amp;eacute;n lo controla el micro autom&amp;aacute;ticamente, es decir, si ejecutamos una instrucci&amp;oacute;n de ensamblador que es una lectura, cambiar&amp;aacute; la pata de forma adecuada y autom&amp;aacute;ticamente.&lt;/p&gt;
&lt;p align="justify"&gt;Pero todav&amp;iacute;a no hemos terminado. Nos falta el reloj, ya que sin &amp;eacute;l todo lo que hemos explicado estar&amp;iacute;a muerto. El reloj no es m&amp;aacute;s que un generador de onda cuadrada (m&amp;aacute;s o menos, he visto relojes con el osciloscopio que me dan serias dudas de que la placa funcione) al que se conectan absolutamente todos los perif&amp;eacute;ricos y el micro, y aqu&amp;iacute; s&amp;iacute;, aqu&amp;iacute; lo v&amp;aacute;lido son los flancos. A cada flanco, se produce un &lt;i&gt;paso&lt;/i&gt;. Es lo que se llama &lt;i&gt;ciclo de reloj&lt;/i&gt;. En algunos micros y hardware son v&amp;aacute;lidos tanto los flancos de subida como los de bajada, en otros s&amp;oacute;lo los de subida o los de bajada.&lt;/p&gt;
&lt;p align="justify"&gt;Ante cada ciclo, se produce un evento en el sistema. Imaginemos que el micro ya sabe qu&amp;eacute; instrucci&amp;oacute;n va a ejecutar. Pongamos por caso que se trate de una lectura de una direcci&amp;oacute;n de RAM. Pasa un ciclo y el micro mueve las patas de los CS y WR, alertando al chip de la RAM. En el caso que nos ocupa, los CS valdr&amp;iacute;an 01, lo que activar&amp;iacute;a la entrada CS de la RAM (y s&amp;oacute;lo de la RAM). Al ciclo siguiente el micro pone en el bus de direcciones la direcci&amp;oacute;n a leer. Dado el CS adecuado, s&amp;oacute;lo la RAM se pondr&amp;aacute; a la escucha, o validar&amp;aacute; lo que quiera que venga despu&amp;eacute;s. En el siguiente ciclo la RAM leer&amp;aacute; del bus de direcciones, y necesitar&amp;aacute; un determinado n&amp;uacute;mero de ciclos m&amp;aacute;s para hacer su trabajo, al cabo de los cuales pondr&amp;aacute; en el bus de datos el valor solicitado, y en el siguiente, el micro lo tomar&amp;aacute;. Esto es s&amp;oacute;lo un posible ejemplo de lo que ocurre. Algunos elementos necesitan un solo ciclo. Por ejemplo, el micro podr&amp;iacute;a poner la direcci&amp;oacute;n, los CS y el WR en un solo ciclo, y la RAM ser tan r&amp;aacute;pida que al siguiente ya tenga la soluci&amp;oacute;n en el bus de datos. En general, cuando un elemento complejo necesita un solo ciclo, es que dicho elemento es capaz de subdividir cada ciclo en varios m&amp;aacute;s de forma interna.&lt;/p&gt;
&lt;p align="justify"&gt;Otra de las cosas que debemos decirle al micro antes de empezar es cu&amp;aacute;ntos ciclos tiene que esperar a que el dato pedido est&amp;eacute; disponible o sea grabado para cada CS o rango de direcciones. De hecho, grabar todos estos valores (y m&amp;aacute;s) es lo que se conoce como &lt;i&gt;startup&lt;/i&gt; del micro. Si os fij&amp;aacute;is, el CS para la ROM es 00, lo que viene a decir que cuando el micro arranque empezar&amp;aacute; a leer a partir de una direcci&amp;oacute;n predefinida (a veces dependiendo de c&amp;oacute;mo se encuentren las &lt;i&gt;patas de arranque&lt;/i&gt;, por llamarlas de alguna manera). Es en esa direcci&amp;oacute;n, y siguientes, en las que se encuentran las instrucciones para ir activando y configurando todos estos elementos.&lt;/p&gt;
&lt;p align="justify"&gt;De hecho, cada micro, cada familia de micros, cada fabricante, lo hace a su manera, indica unas direcciones y unas formas concretas, no s&amp;oacute;lo de c&amp;oacute;mo arranca un micro, sino tambi&amp;eacute;n del tipo de l&amp;oacute;gica, perif&amp;eacute;ricos permisibles, velocidades de reloj, retardos m&amp;aacute;ximos y m&amp;iacute;nimos, y un largu&amp;iacute;simo etc&amp;eacute;tera. Por ejemplo, los micros ARM tienen un encendido m&amp;aacute;s que curioso. Necesitan de un chip que inyecte, a trav&amp;eacute;s de un canal serie, el c&amp;oacute;digo de arranque. Es decir, al encendido el micro est&amp;aacute; muerto, y es un chip externo el que, a trav&amp;eacute;s de una de las patas del micro, inyecte el c&amp;oacute;digo necesario para que &amp;eacute;ste sea capaz de arrancar. Se trata de un sistema de seguridad bastante potente, porque en ese c&amp;oacute;digo podr&amp;iacute;a estar el algoritmo para decodificar una ROM encriptada.&lt;/p&gt;
&lt;p align="justify"&gt;***&lt;/p&gt;
&lt;p align="justify"&gt;Bueno, ya tenemos nuestro micro encendido y funcionando. &amp;iquest;Qu&amp;eacute;? Ah, se me olvidaba, que todav&amp;iacute;a no sabemos c&amp;oacute;mo decirle todo lo que hemos visto. Aqu&amp;iacute; la cosa resulta algo m&amp;aacute;s sencilla, ya que s&amp;oacute;lo hay unas pocas aproximaciones posibles.&lt;/p&gt;
&lt;p align="justify"&gt;En general, cada micro tiene un conjunto de registros &lt;i&gt;especiales&lt;/i&gt;, que es donde nosotros escribiremos y leeremos la configuraci&amp;oacute;n. A veces el registro viene impl&amp;iacute;cito en la instrucci&amp;oacute;n, es decir, existe una &amp;uacute;nica instrucci&amp;oacute;n para modificar dicho elemento. Si tenemos un AX, BX, DX, que vienen codificados en la instrucci&amp;oacute;n, tambi&amp;eacute;n podemos tener un MBAR&amp;hellip;&lt;/p&gt;
&lt;p align="justify"&gt;Cuando uno ejecuta una instrucci&amp;oacute;n en ensamblador, por ejemplo &amp;ldquo;MOV AX,1234&amp;rdquo;, su c&amp;oacute;digo de operaci&amp;oacute;n (lo que realmente est&amp;aacute; leyendo el micro), es 0x87, por lo que, en la ROM, nos encontrar&amp;iacute;amos con los valores hexadecimales 0x87, 0x34, 0x12. Con esto no quiero decir que para un Intel, el c&amp;oacute;digo de operaci&amp;oacute;n de esa instrucci&amp;oacute;n sea 0x87, es solo un ejemplo inventado. &lt;/p&gt;
&lt;p align="justify"&gt;En binario, ese c&amp;oacute;digo de operaci&amp;oacute;n es 10 000 111. Fijaros que lo he dividido en tres grupos. Lo que hace el micro, cuando est&amp;aacute; ejecutando esa instrucci&amp;oacute;n, es leer los dos primeros bits, 10. Esos dos primeros bits le dicen a la unidad de decodificaci&amp;oacute;n que es una instrucci&amp;oacute;n MOV. Podr&amp;iacute;amos tener cuatro combinaciones, 00, 01, 10, y 11. La primera podr&amp;iacute;a ser para JMP, la segunda para CMP, la tercera para MOV y la cuarta para una instrucci&amp;oacute;n multibyte o extendida. Es s&amp;oacute;lo un ejemplo.&lt;/p&gt;
&lt;p align="justify"&gt;Ya sabe que es un MOV, y tambi&amp;eacute;n sabe que los tres bits siguientes son el registro de destino, y los tres &amp;uacute;ltimos el de origen, as&amp;iacute; que sigue decodificando (quiz&amp;aacute;s en un nuevo ciclo de reloj). 000 se corresponde al registro AX, y 111 a c&amp;oacute;digo inmediato, es decir, el registro de origen no es un registro, sino los dos siguientes bytes dentro de la ROM, por lo que inicia la secuencia descrita arriba para obtenerlos, y una vez que lo tiene todo, termina ejecutando el tema y poniendo 0x1234 en el acumulador. Y aqu&amp;iacute; es donde entran los ciclos m&amp;aacute;quina que cada instrucci&amp;oacute;n necesita, que suelen ser diferentes incluso para cada &lt;i&gt;modo&lt;/i&gt; de una misma. Por ejemplo, MOV AX,BX quiz&amp;aacute;s requiera s&amp;oacute;lo dos ciclos, decodificar y ejecutar, pero MOV AX,0x1234 requerir&amp;aacute; 2 ciclos m&amp;aacute;s 4 para obtener el primer byte inmediato m&amp;aacute;s 4 para el segundo, y eso sin contar los de espera hasta que los datos han salido de la ROM.&lt;/p&gt;
&lt;p align="justify"&gt;Si os fij&amp;aacute;is, el orden de los bytes inmediatos en el ROM est&amp;aacute; invertido. Es una de esas cosas que son porque son, sin m&amp;aacute;s justificaci&amp;oacute;n que el fabricante as&amp;iacute; lo ha decidido. Aunque no es realmente cierto, quiz&amp;aacute;s al colocarlos as&amp;iacute; ahorra en puertas l&amp;oacute;gicas en la unidad de decodificaci&amp;oacute;n, pero es otra cosa m&amp;aacute;s a tener en cuenta, y es el orden de los bytes, Little Endian o Big Endian.&lt;/p&gt;
&lt;p align="justify"&gt;Ahora que ya sabemos c&amp;oacute;mo decodifica una instrucci&amp;oacute;n un micro, quiz&amp;aacute;s el c&amp;oacute;digo de operaci&amp;oacute;n 0xc5 m&amp;aacute;s los bytes 0x00 0x1f sean la instrucci&amp;oacute;n para decirle al micro que el MBAR est&amp;aacute; en 0x1f00. Por tanto, nuestras tres primeras instrucciones han sido ejecutadas, y le hemos dicho al micro que, a partir de ahora, los registros especiales est&amp;aacute;n en 0x1f00. &lt;/p&gt;
&lt;p align="justify"&gt;Esto nos lleva a otra forma de configurarlo. Hay micros en los que los registros especiales son simples direcciones de memoria normales y corrientes pero que, en lugar de acceder a memoria normal (sea del tipo que sea), simplemente cambian la configuraci&amp;oacute;n interna del mismo. Quiz&amp;aacute;s escribir 0x01 en la direcci&amp;oacute;n 0xffff sea decirle al micro que est&amp;aacute; usando memoria externa, y que escribir 0x0000 en las direcciones 0xfffe y 0xfffd respectivamente sean decirle que el chip select 0 empieza en 0x0000. Y a su vez al escribir 0x7ffff en las 0xfffc y 0xfffb le estemos diciendo que la direcci&amp;oacute;n final del CS 0 sea esa misma.&lt;/p&gt;
&lt;p align="justify"&gt;Y lo mismo con los dem&amp;aacute;s CS y sus correspondientes registros mapeados en memoria. Esta es la forma m&amp;aacute;s com&amp;uacute;n, pero as&amp;iacute; estamos usando direcciones que no podremos utilizar en nuestros programas, por lo que algunos micros utilizan instrucciones especiales. Por ejemplo, si hacemos MOV 0xffff,0x01, estaremos escribiendo en RAM, pero si hacemos IMOV 0xffff,0x01 lo haremos en la configuraci&amp;oacute;n del micro.&lt;/p&gt;
&lt;p align="justify"&gt;Pero no os asust&amp;eacute;is, en general todo esto ya viene predefinido con los ensambladores y los compiladores mediante definiciones y macros, e incluso a veces los fabricantes implementan construcciones y extensiones a C o a C++ (y a ensamblador) para lidiar con todo esto. Por ejemplo, si en un compilador de C de Imagecraft para Atmel colocamos&lt;/p&gt;
&lt;blockquote&gt;
&lt;p align="justify"&gt;__flash int cero=0;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p align="justify"&gt;en lugar de &lt;/p&gt;
&lt;blockquote&gt;
&lt;p align="justify"&gt;int cero=0;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p align="justify"&gt;ese entero ir&amp;aacute; en ROM en lugar de RAM. Sin embargo, la l&amp;iacute;nea con la extensi&amp;oacute;n, en uno de IAR para el mismo micro, nos colocar&amp;aacute; &lt;i&gt;cero&lt;/i&gt; en la flash interna en lugar de la ROM. Y no quiero entrar en esto, en c&amp;oacute;mo cada fabricante pone las extensiones que les sale de los cojones y como les salen de los cojones, eso dar&amp;iacute;a para otro post con m&amp;aacute;s mala leche que este.&lt;/p&gt;
&lt;p align="justify"&gt;Volviendo al tema que nos ocupa, si ahora queremos leer el estado de bytes de un puerto, una simple instrucci&amp;oacute;n en C no los soluciona:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p align="justify"&gt;unsigned char puerto=PINC;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p align="justify"&gt;El compilador har&amp;aacute; lo que tenga que hacer para que en &lt;i&gt;puerto&lt;/i&gt; est&amp;eacute; la representaci&amp;oacute;n binaria de bits de lo que quiera que haya en dicho puerto. La macro &lt;i&gt;PINC&lt;/i&gt; tiene su intr&amp;iacute;ngulis, ya que podr&amp;iacute;a ser cualquier cosa, desde una llamada a una funci&amp;oacute;n intr&amp;iacute;nseca al compilador hasta una simple lectura de una direcci&amp;oacute;n f&amp;iacute;sica o una instrucci&amp;oacute;n en ensamblador, quiz&amp;aacute;s RMOV 0xff33,puerto.&lt;/p&gt;
&lt;p align="justify"&gt;Pongamos por caso que hayamos conectado al bit0 del puerto C (que se corresponder&amp;aacute; con una pata del micro), un sensor de una puerta, que pondr&amp;aacute; dicho bit a 1 (l&amp;oacute;gico) cuando la puerta se abra. Por tanto, el c&amp;oacute;digo:&lt;/p&gt;
&lt;pre&gt;void main(void)
{
    inicializa_hardware();
    for(;;)
    {
        if((PINC&amp;amp;0x01)!=0)
        {
            suena_sirena();
        }
    }
}&lt;/pre&gt;
&lt;p align="justify"&gt;Nos servir&amp;aacute; para construir una alarma. Quiz&amp;aacute;s la funci&amp;oacute;n &lt;i&gt;suena_sirena()&lt;/i&gt; escriba un 1 en otro bit de otro puerto, cuya correspondiente pata del micro vaya conectada a un transistor que a su vez activar&amp;aacute; un rel&amp;eacute; que pondr&amp;aacute; en marcha una sirena&amp;hellip;&lt;/p&gt;
&lt;p align="justify"&gt;Dentro de &lt;i&gt;inicializa_hardware()&lt;/i&gt; habremos puesto sentencias como:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p align="justify"&gt;PORTC=0xff; //Encender todos los pull-up internos del Puerto C
    &lt;br /&gt;DDRC=0x00; //Poner el Puerto C como entradas
    &lt;br /&gt;PORTD=0x00; //Quitar los pull-ups del Puerto D
    &lt;br /&gt;DDRD=0x01; //Poner el Pin0 del Puerto D como salida
    &lt;br /&gt;PIND=0x00; //Apagar la sirena.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p align="justify"&gt;Los comentarios son auto descriptivos, y nos ense&amp;ntilde;an c&amp;oacute;mo poner un puerto como elemento de entrada (para leer datos de &amp;eacute;l) o de salida (para escribir), si queremos tener pull-ups (unas resistencias especiales para a&amp;ntilde;adir carga), etc. Luego esto ser&amp;aacute; traducido a c&amp;oacute;digo ensamblador del micro correspondiente, y de nuevo la parte izquierda del igual son, en este caso, macros.&lt;/p&gt;
&lt;p align="justify"&gt;De todos modos la cosa no es tan sencilla. En este caso da igual que escribamos en un puerto de entrada, el micro lo ignorar&amp;aacute;, pero en otros microprocesadores no se puede hacer a riesgo de romper algo, por lo que operaciones mixtas requieren t&amp;eacute;cnicas de doble buffer, como mantener un juego del estado de entradas o salidas anteriores (lo que de paso nos dar&amp;iacute;a para mantener flancos l&amp;oacute;gicos, que nada tienen que ver con los f&amp;iacute;sicos de la placa).&lt;/p&gt;
&lt;p align="justify"&gt;Por si no ha quedado claro, hacer algo como PINC|=0x01; significa leer el estado del puerto C y, sin importarnos cu&amp;aacute;l es el valor del bit0, ponerlo a uno (ya que una o l&amp;oacute;gica con uno de los dos bits a 1 siempre resultar&amp;aacute; en 1) sin modificar los dem&amp;aacute;s y volver a escribir el resultado en el puerto. Como antes hemos le&amp;iacute;do los valores, s&amp;oacute;lo estamos cambiando el bit0. Pero ocurre que en algunos micros las salidas no se pueden leer (no es que no se puedan, sino que no leen nada coherente), por lo que tenemos que mantener variables de estado (de nuevo el doble buffer). &lt;/p&gt;
&lt;p align="justify"&gt;Esta operaci&amp;oacute;n de escritura en ese puerto, quiz&amp;aacute;s sea compilada como una escritura en una direcci&amp;oacute;n de memoria, o la ejecuci&amp;oacute;n de una instrucci&amp;oacute;n especial de ensamblador, pero el resultado final ser&amp;aacute; que la pata del microprocesador que se corresponda con ese bit pasar&amp;aacute; a estar a un uno l&amp;oacute;gico, que realmente podr&amp;iacute;a ser ponerse a 5V, o a cero, o cambiar su estado, o ejecutar un flanco de subida, o de bajada, o uno de subida y luego otro de bajada, o justo al rev&amp;eacute;s. Todo depender&amp;aacute; de qu&amp;eacute; micro y c&amp;oacute;mo est&amp;eacute; configurado.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=161107" width="1" height="1"&gt;</content><author><name>RFOG</name><uri>http://geeks.ms/members/RFOG/default.aspx</uri></author><category term="c++" scheme="http://geeks.ms/blogs/rfog/archive/tags/c_2B002B00_/default.aspx" /><category term="rationale" scheme="http://geeks.ms/blogs/rfog/archive/tags/rationale/default.aspx" /><category term="hardware" scheme="http://geeks.ms/blogs/rfog/archive/tags/hardware/default.aspx" /><category term="lenguajes" scheme="http://geeks.ms/blogs/rfog/archive/tags/lenguajes/default.aspx" /></entry><entry><title>Cómo salta Windows entre anillos (Modo Kernel y modo Usuario)</title><link rel="alternate" type="text/html" href="/blogs/rfog/archive/2009/11/21/c-243-mo-salta-windows-entre-anillos-modo-kernel-y-modo-usuario.aspx" /><id>/blogs/rfog/archive/2009/11/21/c-243-mo-salta-windows-entre-anillos-modo-kernel-y-modo-usuario.aspx</id><published>2009-11-21T13:37:03Z</published><updated>2009-11-21T13:37:03Z</updated><content type="html">&lt;p align="justify"&gt;Esta semana estamos de fiesta, y es que una de mis pasiones en el desarrollo siempre ha sido verle las tripas a Windows, y a ello vamos. Antes de nada, lo que voy a contar aquí es un resumen del punto &lt;i&gt;System Service Dispatching&lt;/i&gt; del capítulo 3 de &lt;i&gt;Windows Internals &lt;/i&gt;5ª edición, pero es un resumen un poco &lt;i&gt;especial&lt;/i&gt; porque voy a añadir cosas de mi cosecha, como siempre hago, ya que no es cosa de ir parafraseando lo que voy aprendiendo/recordando.&lt;/p&gt;  &lt;p align="justify"&gt;En entradas anteriores, y algunas veces en los foros, he comentado sobre &lt;i&gt;saltos entre anillo 0 y anillo 3&lt;/i&gt;, y aquí voy a explicar de pasada lo que significa. Un microprocesador moderno (y no tan moderno), cuenta con un juego de instrucciones en cierta medida especiales, instrucciones que son necesarias para configurar el hardware y el propio funcionamiento del software. Hablamos aquí de las interrupciones y toda su parafernalia asociada, del control de la memoria virtual, del acceso directo a hardware (es decir, escribir o leer en una dirección de memoria o en un puerto en el que no hay tal, sino alguna electrónica que debe reaccionar en base a dicha lectura o escritura), etc.&lt;/p&gt;  &lt;p align="justify"&gt;Esas instrucciones son peligrosas de usar, y en general no deben estar disponibles para los programas normales, ya que entonces un error podría llevar a la caída total del sistema o incluso a la rotura de algún elemento electrónico.&lt;/p&gt;  &lt;p align="justify"&gt;Es decir, que podríamos dividir el juego de instrucciones de un microprocesador en dos grandes grupos: aquellas que no son necesarias para que un programa funcione normalmente y las que, si se usan de forma incorrecta, pueden terminar armando un buen pirifostio.&lt;/p&gt;  &lt;p align="justify"&gt;Pues básicamente eso son los anillos 0 y 3. En el 0 están las instrucciones peligrosas, en el 3 las que cualquier programa puede usar, y si un programa normal utiliza una del cero, generará una excepción (¿De qué me sonará esto?) que será capturada por el sistema operativo y manejada a su antojo. Aunque realmente no es del todo así, para nuestro propósito es suficiente. &lt;/p&gt;  &lt;p align="justify"&gt;(Si os dais cuenta, he hablado del 0 y del 3, pero también hay un 1 y un 2, que Windows no utiliza. Digamos que la separación de las instrucciones en estos distintos niveles permiten una serie de facilidades a la hora de construir software de sistemas, ya sean sistemas operativos o aplicaciones que vayan a correr en un microprocesador con estas características, lo que ocurre es que Windows aprovecha estos niveles únicamente de una sola forma, que llama modo usuario y modo kernel).&lt;/p&gt;  &lt;p align="justify"&gt;Pues bien, el &lt;i&gt;kelmer&lt;/i&gt;, uis, perdón, el kernel, la mayoría de los drivers, y el motor gráfico (que fue ampliamente criticado en su momento pero que permitió que NT 4.0 pudiera ser usado en ordenadores no tan potentes) se ejecutan en el anillo 0, y los demás subsistemas (incluido Win32) en el 3. De esta forma un programador chapucero (o un compilador) sólo podrá tumbar su programa y nada más. Recordemos los días de Windows 3.x y DOS en los cuales tumbar por completo el sistema era tan fácil como ejecutar dos instrucciones de ensamblador seguidas: cli y luego sti, o al revés, ya no me acuerdo.&lt;/p&gt;  &lt;p align="justify"&gt;Una aplicación llama a una función, que debe terminar siendo ejecutada dentro del kernel (por ejemplo, abrir y leer de un fichero, cosa que necesita que los drivers de disco hagan trabajo de bajo nivel sobre la controladora y sobre el propio disco). Pongamos que nuestro programa llama a &lt;i&gt;WriteFile()&lt;/i&gt;, y nos da igual que sea una aplicación .NET llamando a sus clases, ya que terminará en esa función. Esa función, que está en Kernel32.dll y pertenece al subsistema Win32, llamará a NtWriteFile(), que está en Ntdll.dll y no pertenece a ningún subsistema, sino que está disponible para cualquiera de ellos. Esta función llamará entonces a KiSystemService(), que está en Ntoskrnl.exe y se ejecuta en el anillo 0 en lugar del 3. Finalmente, esta última función hará lo que tenga que hacer llamando a otras funciones del kernel y de los drivers hasta que al final devolverá el resultado hacia atrás hasta nuestra aplicación.&lt;/p&gt;  &lt;p align="justify"&gt;Fácil, ¿no? Pues no, porque si nuestra aplicación hubiera llamado a WriteFile() con algún parámetro mal que fuera crítico (y se me ocurre pasar un valor aleatorio diferente de cero al handle del fichero sobre el que queremos escribir), lo más seguro es que termináramos en una pantalla azul (como más o menos ocurría en Windows 3.x y a veces en Windows 9x). Además, es muy posible que durante el procesamiento de la función, se salte varias veces entre el modo kernel y el user por necesidades del guión.&lt;/p&gt;  &lt;p align="justify"&gt;Pero todavía hay más, ya que no hemos tenido en cuenta que el controlador de tiempos y de procesos puede cortar en cualquier momento esa llamada para atender otros procesos o incluso hilos de nuestra aplicación. Vamos, que no es fácil ni de lejos.&lt;/p&gt;  &lt;p align="justify"&gt;¿Cómo se produce el salto entre el anillo 3 y el 0, que hemos descrito más arriba? Pues depende del procesador que estemos usando. En la época de Windows 9x (y de la parte en modo protegido de Windows 3.x cuando la había), y para micros antiguos, NtWriteFile(), después de verificar que los parámetros recibidos son correctos, coloca en varios registros del procesador lo necesario, y ejecuta la instrucción &lt;i&gt;int 0x2e&lt;/i&gt;, que genera una excepción si se hace desde el anillo 3. Esta excepción es recogida por el Kernel, que mediante los parámetros que hay en los registros determina si es una petición válida (y si no lo es protestará) y la procesará mediante la ejecución de la función correspondiente situada en un array de punteros a función que se llama &lt;i&gt;System Service Dispatch Table&lt;/i&gt;, de las que creo que hay varias. Básicamente, lo que está haciendo es recibir un índice que se corresponde a una posición dentro del array de punteros, y como nos equivoquemos con esto la hemos cagado a base de bien, y es por eso por lo que antes del salto entre anillos se verifican los parámetros. El retorno al anillo 3 se produce con la ejecución de la instrucción &lt;i&gt;iretd.&lt;/i&gt;&lt;/p&gt;  &lt;p align="justify"&gt;En micros Intel más modernos, el salto se hace mediante la instrucción &lt;i&gt;sysenter&lt;/i&gt; y la vuelta mediante &lt;i&gt;sysexit&lt;/i&gt; (o &lt;i&gt;iret&lt;/i&gt; si estamos en modo depuración). En un AMD las instrucciones son &lt;i&gt;syscall&lt;/i&gt; y &lt;i&gt;sysret&lt;/i&gt;.&lt;/p&gt;  &lt;p align="justify"&gt;Y finalmente, en micros de 64 bits con la arquitectura x64 las instrucciones son las mismas que en el AMD (por que fueron los primeros en implementarla) y en la I64, &lt;i&gt;epc&lt;/i&gt;.&lt;/p&gt;  &lt;p align="justify"&gt;Si os dais cuenta, dependiendo del microprocesador se hace de una u otra forma, lo que puede ser un serio quebradero de cabeza. Lo que hace Windows al arrancar un sistema de 32 bits es instalar la instrucción correcta en una posición de memoria y juego ejecutar sobre ella, con lo que a lo anterior añadimos un nuevo nivel de indirección. &lt;/p&gt;  &lt;p align="justify"&gt;La secuencia completa de paso del anillo 3 al 0 consiste, más o menos, en lo siguiente: primero se verifican los parámetros recibidos de la forma más completa posible, luego se ejecuta la instrucción que hay en cierta posición de memoria, que a su vez generará una excepción, que será controlada por el sistema operativo, que mirará si los parámetros son correctos, y si lo son volverá a saltar sobre un puntero a puntero a función, y finalmente lo que haya allí hará el trabajo. &lt;/p&gt;  &lt;p align="justify"&gt;Eso para un solo salto. Imaginaros cuántos son necesarios para que nuestro programa, y el sistema operativo funcione. Y no hemos hablado de que en cada una de esos pasos es necesario que la pila se guarde o se recupere, y que los datos deben ser copiados desde la pila de modo user a la de modo kernel para evitar que la aplicación pueda modificarlos en medio de una operación interna…&lt;/p&gt;  &lt;p align="justify"&gt;En un sistema x64 la operación es algo más sencilla porque la instrucción de salto es siempre la misma y no es necesaria la indirección extra sobre la instrucción ya que da igual que el microprocesador sea un Intel o un AMD.&lt;/p&gt;  &lt;p align="justify"&gt;Esto quizás te presente una duda en el caso de equipos de 32 bits: ¿por qué no está cableada dicha instrucción y simplemente a la hora de instalar Windows o de arrancarlo, el cargador pone en memoria el juego de DLLs correcto? Pues realmente no tengo ni idea, lo que sí tengo claro es que en ese caso Windows debería contar con al menos 4 juegos completos de DLLs y o bien elegir el necesario durante la instalación o casi cuadriplicar el espacio ocupado en disco. Lo que sí es cierto es que si se hubiera hecho así, el Windows de 32 bits funcionaría sensiblemente más rápido… o no.&lt;/p&gt;  &lt;p align="justify"&gt;Sólo nos queda ver, por mor de completitud, cómo funciona internamente el kernel sobre sí mismo. Supongamos por un momento que el kernel necesita acceder a la funcionalidad que hay en WriteFile(), pero en lugar de llamar a esta función directamente, lo que hace es llamar directamente a la rutina a la que se está apuntando en la tabla SSDT y santas pascuas, ya que en principio no se necesita verificar los parámetros que se suponen son correctos, y aparte de eso ya estamos en el anillo 0. No obstante, un driver no puede hacerlo así porque Microsoft no se fía de ellos, y es por ello que existen unas funciones que tiene como prefijo Zw y que son las que llamarán a su homónimo apuntado por la SSDT después de realizar las verificaciones –menos que si se llamara desde el anillo 3- oportunas.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=160981" width="1" height="1"&gt;</content><author><name>RFOG</name><uri>http://geeks.ms/members/RFOG/default.aspx</uri></author><category term="windows" scheme="http://geeks.ms/blogs/rfog/archive/tags/windows/default.aspx" /><category term="vista" scheme="http://geeks.ms/blogs/rfog/archive/tags/vista/default.aspx" /><category term="hardware" scheme="http://geeks.ms/blogs/rfog/archive/tags/hardware/default.aspx" /><category term="libros" scheme="http://geeks.ms/blogs/rfog/archive/tags/libros/default.aspx" /><category term="Win32" scheme="http://geeks.ms/blogs/rfog/archive/tags/Win32/default.aspx" /><category term="Windows 7" scheme="http://geeks.ms/blogs/rfog/archive/tags/Windows+7/default.aspx" /></entry><entry><title>Eligiendo qué hacer cuando pete nuestra aplicación</title><link rel="alternate" type="text/html" href="/blogs/rfog/archive/2009/11/19/eligiendo-qu-233-hacer-cuando-pete-nuestra-aplicaci-243-n.aspx" /><id>/blogs/rfog/archive/2009/11/19/eligiendo-qu-233-hacer-cuando-pete-nuestra-aplicaci-243-n.aspx</id><published>2009-11-19T17:53:00Z</published><updated>2009-11-19T17:53:00Z</updated><content type="html">&lt;p align="justify"&gt;En la &lt;a href="http://geeks.ms/blogs/rfog/archive/2009/11/18/de-excepciones-del-depurador-de-windows-y-de-visual-studio.aspx"&gt;entrada anterior&lt;/a&gt; expliqu&amp;eacute; qu&amp;eacute; ocurre cuando una aplicaci&amp;oacute;n peta y se genera una excepci&amp;oacute;n no controlada (o controlada pero relanzada), y en esta voy a explicar c&amp;oacute;mo podemos, desde nuestro propio programa, configurar el modo en que eso ocurre. Pero antes una introducci&amp;oacute;n.&lt;/p&gt;
&lt;p align="justify"&gt;En algunos lados he dicho que las excepciones son caras. Con eso no me refiero a que cuesten dinero, sino a que es un tipo de caracter&amp;iacute;stica que resulta muy complicada de procesar y que a veces requiere de bastante tiempo de proceso. Cuando se dispara una interrupci&amp;oacute;n en una aplicaci&amp;oacute;n, sobre todo si ocurre en el lado del kernel, &amp;eacute;ste tiene que entrar y salir varias veces entre su modo y el de usuario, operaciones que no son baratas (de nuevo no en dinero, aunque lo mismo en su servidor en producci&amp;oacute;n s&amp;iacute;) ya que significan saltar entre los anillos 0 y 3 del procesador. Aparte de eso, se debe recorrer la pila (a ambos lados de los anillos) para ir buscando el controlador adecuado, ejecutarlo y en la mayor&amp;iacute;a de casos continuar con la b&amp;uacute;squeda. &lt;/p&gt;
&lt;p align="justify"&gt;Cuando ponemos un bloque try/catch, o __try/__except &amp;oacute; __try/__finally, el compilador deja &amp;ldquo;marcas&amp;rdquo; en la pila, &amp;ldquo;marcas&amp;rdquo; que ser&amp;aacute;n le&amp;iacute;das por el controlador de excepciones. Dependiendo de c&amp;oacute;mo lo hayamos hecho, y el n&amp;uacute;mero de bloques y de controladores, el sistema tendr&amp;aacute; que salvar y restaurar el estado de la pila y de la aplicaci&amp;oacute;n para ir ejecutando los diferentes bloques de captura, y a veces incluso se necesita de cierta &amp;ldquo;inteligencia&amp;rdquo; para que la ejecuci&amp;oacute;n sea la correcta. El tema queda bastante claro una vez que se han le&amp;iacute;do los cap&amp;iacute;tulos de los dos libros que mencion&amp;eacute;, con una excepci&amp;oacute;n: que esos recorridos requieren tiempo, sobre todo si hay saltos entre anillo 0 y 3, por lo que en general el uso de excepciones est&amp;aacute; para eso: para ser usadas cuando realmente se produzca una, y no alegremente como una mera caracter&amp;iacute;stica de nuestro lenguaje.&lt;/p&gt;
&lt;p align="justify"&gt;Dicho esto, considero que el ejemplo que Jeffrey Ritcher pone al final del cap&amp;iacute;tulo 25 no es muy correcto, no porque est&amp;eacute; mal, sino porque realizar gesti&amp;oacute;n de memoria mediante excepciones me parece que es matar moscas a ca&amp;ntilde;onazos&amp;hellip; aparte del desperdicio de la misma. Ritcher crea una hoja de c&amp;aacute;lculo de un tama&amp;ntilde;o predefinido pero sin asignar ning&amp;uacute;n tipo de memoria. Luego, ante cada requerimiento de que una celda sea llenada con algo, intenta escribir en la posici&amp;oacute;n. Si ya hay memoria asignada todo ir&amp;aacute; bien, pero si no, se disparar&amp;aacute; una excepci&amp;oacute;n que asignar&amp;aacute; un bloque a dicha celda. La barbaridad est&amp;aacute; en que cada asignaci&amp;oacute;n, aunque sea de un solo byte, asignar&amp;aacute; 4KB (que es el tama&amp;ntilde;o de p&amp;aacute;gina de RAM), y en que el gasto de la excepci&amp;oacute;n y su control es enormemente m&amp;aacute;s caro que simplemente comprobar si la memoria est&amp;aacute; asignada o no. A no ser que se me escape algo, como ejemplo sobre el funcionamiento de las excepciones, vale, pero como ejemplo de algoritmo gen&amp;eacute;rico, no.&lt;/p&gt;
&lt;p align="justify"&gt;De todos modos, el sistema de excepciones es my potente y vers&amp;aacute;til, y con la combinaci&amp;oacute;n del registro, podemos configurar a base de bien el comportamiento de las no controladas. &lt;i&gt;Windows Internals&lt;/i&gt; lista 25 claves para cambiar el comportamiento, alguna de ellas tan radicales como hacer que ni siquiera se ejecute &lt;i&gt;WerFault.exe&lt;/i&gt; y nuestra aplicaci&amp;oacute;n desaparezca de forma silenciosa.&lt;/p&gt;
&lt;p align="justify"&gt;Pero como dir&amp;iacute;a el personaje de los dibujos animados, &lt;i&gt;no se vayan todav&amp;iacute;a, que hay m&amp;aacute;s&lt;/i&gt;. Aparte de poder instalar y controlar ciertas funciones de control de excepciones, podemos configurar el modo con que nuestra aplicaci&amp;oacute;n se comunica con el gestor de las mismas. Es decir, mediante ciertas llamadas a funciones de Win32, podemos decirle al sistema &lt;i&gt;WER&lt;/i&gt; c&amp;oacute;mo debe comportarse, qu&amp;eacute; ficheros adjuntar, etc.&lt;/p&gt;
&lt;p align="justify"&gt;La mayor&amp;iacute;a de las funciones que voy a citar aqu&amp;iacute; de pasada, se encuentran dentro de &lt;i&gt;kernel32.dll&lt;/i&gt; y para usarlas debemos incluir &lt;i&gt;werapi.h.&lt;/i&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;div align="justify"&gt;&lt;i&gt;WerSetFlags()/WerGetFlags()&lt;/i&gt;. Cambiamos o leemos si queremos que se incluya el &lt;i&gt;heap&lt;/i&gt; (mont&amp;iacute;culo) en el informe, si se suspender&amp;aacute;n todos los hilos o s&amp;oacute;lo el que fall&amp;oacute;, si se a&amp;ntilde;adir&amp;aacute; el informe a la lista de errores, y si se enviar&amp;aacute; o no a Microsoft. &lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;div align="justify"&gt;&lt;i&gt;WerAddExcludedApplication()/WerRemoveExcludedApplication()&lt;/i&gt;. A&amp;ntilde;adir o eliminar una aplicaci&amp;oacute;n a la lista de aplicaciones excluidas de la generaci&amp;oacute;n de informes.&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;div align="justify"&gt;&lt;i&gt;WerRegisterFile()/WerUnregisterFile()&lt;/i&gt;. A&amp;ntilde;adir o quitar el fichero indicado al informe.&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;div align="justify"&gt;&lt;i&gt;WerRegisterMemoryBlock()/WerUnregisterMemoryBlock()&lt;/i&gt;.&lt;i&gt; &lt;/i&gt;A&amp;ntilde;adir/Qutar un volcado de un &amp;aacute;rea de la memoria de nuestro programa.&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p align="justify"&gt;Tambi&amp;eacute;n podemos crear un informe desde nuestro programa cuando queramos. Los pasos a seguir son:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;div align="justify"&gt;Llamar a &lt;i&gt;WerReportCreate()&lt;/i&gt;, que inicia el informe.&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;div align="justify"&gt;Llamar tantas veces a &lt;i&gt;WerReportSetParameter()&lt;/i&gt; como par&amp;aacute;metros queramos cambiar.&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;div align="justify"&gt;Llamar tantas veces a &lt;i&gt;WerReportAddDump()&lt;/i&gt; como bloques de memoria queramos incluir.&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;div align="justify"&gt;Llamar tantas veces a &lt;i&gt;WerReportAddFile()&lt;/i&gt; como ficheros del tipo que sean queramos incluir.&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;div align="justify"&gt;Llamar a &lt;i&gt;WerReportSetUIString()&lt;/i&gt; para a&amp;ntilde;adir opciones a la pantalla de WerFault.exe.&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;div align="justify"&gt;Llamar a &lt;i&gt;WerReportSubmit()&lt;/i&gt;, que dependiendo de la configuraci&amp;oacute;n para el programa y/o gen&amp;eacute;ricas que se tengan, enviar&amp;aacute; o no, preguntar&amp;aacute; o no, etc. qu&amp;eacute; hacer con el informe.&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;div align="justify"&gt;Llamar a &lt;i&gt;WerReportCloseHandle() &lt;/i&gt;para terminar con el tema.&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p align="justify"&gt;Como pod&amp;eacute;is ver, la cosa es muy potente, y puede ser enormemente &amp;uacute;til en determinadas situaciones. Imaginemos que nuestra aplicaci&amp;oacute;n est&amp;eacute; petando en casa del cliente y no haya modo de ver qu&amp;eacute; pu&amp;ntilde;etas pasa. La generaci&amp;oacute;n de informes a demanda podr&amp;iacute;a ser la soluci&amp;oacute;n. Lo que no he visto es c&amp;oacute;mo recibir e interpretar esos informes.&lt;/p&gt;
&lt;p align="justify"&gt;Tambi&amp;eacute;n podemos usar estas funciones cuando sea nuestra aplicaci&amp;oacute;n la que est&amp;eacute; controlando la excepci&amp;oacute;n, pero debemos ser cuidadosos ya que &amp;eacute;sta podr&amp;iacute;a estar tan estropeada que el uso de todo esto volviera a genera nuevas excepciones que terminaran en el mismo c&amp;oacute;digo, que a su vez generara otras que&amp;hellip;&lt;/p&gt;
&lt;p align="justify"&gt;Se supone que Windows es lo suficientemente inteligente como para detener la cadena, pero como yo ya he visto m&amp;aacute;s de una vez petar de forma continua a una aplicaci&amp;oacute;n en Windows Vista hasta que la he matado desde el administrador de tareas, debemos ser cuidadosos con su uso.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=160861" width="1" height="1"&gt;</content><author><name>RFOG</name><uri>http://geeks.ms/members/RFOG/default.aspx</uri></author><category term="c++" scheme="http://geeks.ms/blogs/rfog/archive/tags/c_2B002B00_/default.aspx" /><category term="Sistemas Operativos" scheme="http://geeks.ms/blogs/rfog/archive/tags/Sistemas+Operativos/default.aspx" /><category term="windows" scheme="http://geeks.ms/blogs/rfog/archive/tags/windows/default.aspx" /><category term="Visual Studio" scheme="http://geeks.ms/blogs/rfog/archive/tags/Visual+Studio/default.aspx" /><category term="vista" scheme="http://geeks.ms/blogs/rfog/archive/tags/vista/default.aspx" /><category term="hardware" scheme="http://geeks.ms/blogs/rfog/archive/tags/hardware/default.aspx" /><category term="libros" scheme="http://geeks.ms/blogs/rfog/archive/tags/libros/default.aspx" /><category term="lenguajes" scheme="http://geeks.ms/blogs/rfog/archive/tags/lenguajes/default.aspx" /><category term="Win32" scheme="http://geeks.ms/blogs/rfog/archive/tags/Win32/default.aspx" /><category term="Windows 7" scheme="http://geeks.ms/blogs/rfog/archive/tags/Windows+7/default.aspx" /></entry><entry><title>De excepciones, del depurador, de Windows y de Visual Studio</title><link rel="alternate" type="text/html" href="/blogs/rfog/archive/2009/11/18/de-excepciones-del-depurador-de-windows-y-de-visual-studio.aspx" /><id>/blogs/rfog/archive/2009/11/18/de-excepciones-del-depurador-de-windows-y-de-visual-studio.aspx</id><published>2009-11-18T16:54:09Z</published><updated>2009-11-18T16:54:09Z</updated><content type="html">&lt;p align="justify"&gt;Esto leyendo la quinta edición de &lt;i&gt;&lt;a href="http://www.microsoft.com/learning/en/us/Book.aspx?ID=12069&amp;amp;locale=en-us"&gt;Windows Internals,&lt;/a&gt;&lt;/i&gt; que cubre Windows Vista y Windows Server 2008 y es la última versión disponible del libro. Allá por los años del Windows 95 y del NT 4.0, un poco antes, un poco después, estaba yo muy interesado en las tripillas de los sistemas operativos, y aparte de empacharme con algún que otro mamotreto genérico sobre el tema, le di caña a los equivalentes, como &lt;i&gt;Windows 95, al descubierto&lt;/i&gt;, o el &lt;i&gt;Windows NT&lt;/i&gt; de Helen Custer, así como otros de similar temática. Vamos, que prácticamente me leí todo lo que pude conseguir sobre las interioridades de esos sistemas operativos.&lt;/p&gt;  &lt;p align="justify"&gt;Pero desde hace un tiempo me veo en la tesitura de que, conversando aquí y allí, me he dado cuenta de que me he quedado bastante obsoleto en el tema, con cosas que no sólo han sido mejoradas, sino que ahora funcionan de forma completamente diferente, así que me he puesto las pilas y le estoy dando un buen repaso al libro…&lt;/p&gt;  &lt;p align="justify"&gt;Bueno, pues como iba diciendo, el capítulo 3 del citado no es que sea nada del otro mundo. Bueno, sí, lo cierto es que como no sepas de programación de hardware y hayas hecho algo, te vas a quedar poco menos que a dos velas con muchas de las cosas que aparecen, ya que tienen que ver con la gestión de interrupciones, tanto de software como de hardware, así como las excepciones y demás intríngulis que todo sistema operativo ha de cumplir. &lt;/p&gt;  &lt;p align="justify"&gt;Personalmente yo he hecho un par de proyectos basados en un microprocesador, aunque generalmente, cuando lo hago, suelo trastear con microcontroladores más o menos potentes, y la verdad es que muchas de las cosas que aparecen ahí explicadas, con la evidente diferencia entre un sistema operativo como es Windows y lo que un mindundi como yo haya podido hacer, me las he encontrado en mis desarrollos. Tener en cuenta las prioridades y los niveles de las interrupciones, programarlos y cambiarlos en tiempo real, instalar y quitar vectores de interrupción, etc.&lt;/p&gt;  &lt;p align="justify"&gt;Por lo menos eso es de lo que trata la parte del capítulo 3 que he leído, que ciertamente me parece demasiado detallista en cosas que, la verdad, a no ser que vayas a meterte de lleno en la creación de drivers primarios para Windows, de poco te sirve. Y si sabes de sistemas operativos, lo único llamativo es que te enteras de que Windows no es mucho más diferente que otros sistemas.&lt;/p&gt;  &lt;p align="justify"&gt;Volviendo al tema (lo que me mola irme por las ramas), sobre la página ciento y pico (je je, me quedan todavía más de mil cien por leer, ¡qué emoción!) se pone a hablar del control de las excepciones del sistema operativo, y cómo son controladas en conjunción con el software de aplicación (ese que tu y yo hacemos) y el propio sistema. Y entonces te dice que si no tienes claro cómo funciona a nivel de programador, que mires los capítulos finales de &lt;i&gt;Windows via C/C++&lt;/i&gt;. Y como resulta que tengo ese libro en la lista de pendientes (hace unos años leí y estudié la misma versión pero mucho más antigua, y encima en castellano), pues dejé uno y me puse con el otro, máxime recordando que fueron precisamente esos capítulos los que no leí en la edición anterior.&lt;/p&gt;  &lt;p align="justify"&gt;El sistema de excepciones de Windows es muy potente y versátil, y todos deberíamos saber lo básico sobre él. Pero no, no voy a entrar en detalles sobre el mismo, simplemente os diré que funciona muy parecido a las excepciones de un lenguaje de programación, con la salvedad de que es el sistema operativo el que las lanza y las gestiona si no lo has hecho tu.&lt;/p&gt;  &lt;p align="justify"&gt;En Windows Vista y siguientes existe una aplicación que se llama &lt;i&gt;WerFault.exe&lt;/i&gt; y que seguro que habéis visto en ejecución. De hecho, cada vez que os peta un programa, es esa aplicación la que toma el control y saca la barra de progreso moviéndose y te permite unas u otras acciones una vez que ha hecho sus deberes.&lt;/p&gt;  &lt;p align="justify"&gt;Es decir, cuando una aplicación genera una excepción, o el sistema operativo dispara una causada por la aplicación (por ejemplo, una división entre cero o una escritura fuera de rango), se trastea con la pila de tu programa y se busca un controlador de excepción adecuado. Ojo, no estamos hablando de bloques try/catch, sino de bloques __try/__except… aunque a veces el control termina también en un catch, sobre todo si usamos C++ y hemos habilitado la compatibilidad de control de excepciones del sistema operativo (y esto no viene explicado así en el libro, que asume la compatibildad). En .NET no sé qué ocurrirá, pero no creo que haya mucha diferencia.&lt;/p&gt;  &lt;p align="justify"&gt;Si nuestro programa tiene un manejador para esa excepción, se ejecutará, y dependiendo de lo que devuelva, se reintentará la instrucción (de código máquina, así que ojo) que generó la excepción, se continuará como si nada hubiera pasado (y en este caso podríamos liarla todavía más gorda), o se seguirá buscando otro nuevo manejador. Es decir, independientemente de lo que quiera que hagamos en nuestro controlador, podemos decirle al sistema operativo que reintente, que ignore o que busque otro controlador más.&lt;/p&gt;  &lt;p align="justify"&gt;Una vez que se han recorrido todos los controladores adecuados, además de dos más extra que podemos instalar mediante &lt;i&gt;AddVectoredExceptionHandler()&lt;/i&gt; y &lt;i&gt;SetUnhandledExceptionFilter()&lt;/i&gt;, y siempre que se haya llegado al final de toda la cadena de excepciones (que es algo más larga y compleja de lo que aquí he expuesto) sin haber sido detenida, Windows lanzará el citado programa, y le pasará un manejador al proceso que está fallando, aparte de detener por completo la ejecución de todos sus hilos (en XP sólo se detenía el que fallaba) mediante unas APIs ALPC no documentadas.&lt;/p&gt;  &lt;p align="justify"&gt;Este programa, en base a algunas claves del registro, hará una cosa u otra. Como ha recibido los manejadores en modo heredado, tendrá control sobre el programa que está fallando. Aparte de añadir el evento correspondiente, podrá enviar el informe a Microsoft, o añadirlo a la lista de pendientes. Incluso existe la posibilidad de que ni siquiera aparezca, haciendo todas sus tareas de forma oculta, o incluso que no haga ninguna. Podemos incluso filtrar el comportamiento según qué aplicación haya fallado.&lt;/p&gt;  &lt;p align="justify"&gt;Después de que ha hecho sus tareas internas, si existe algún depurador registrado y si la configuración (o lo que hayamos elegido) lo permite, abrirá el programa &lt;i&gt;vsjitdebugger.exe&lt;/i&gt; que mostrará los depuradores registrados. De nuevo este programa recibe los manejadores de forma heredada, y mientras, nuestra aplicación está completamente muerta, esperando. Una vez que hemos elegido un depurador, éste será ejecutado pasando, otra vez, la información necesaria para que sea capaz de buscar y localizar la aplicación que ha fallado.&lt;/p&gt;  &lt;p align="justify"&gt;Es entonces cuando ésta se abrirá dentro del depurador, y si están disponibles los símbolos y demás, podremos ver qué ha fallado y por qué.&lt;/p&gt;  &lt;p align="justify"&gt;Si os fijáis, el tema no es sencillo ni de lejos. En primer lugar, el programa fallante no puede hacer nada porque podría estar en un estado indeterminado, con la memoria o la pila completamente corruptas, así que es el sistema operativo el que debe tomar el control y lanzar una nueva aplicación que se encargue de todo el paripé, que a su vez lanzará un depurador que no es tal, sino un &lt;i&gt;concentrador de depuradores&lt;/i&gt;, que al final sí, lanzará el depurador elegido, que tomará bajo su ala a nuestro programa petado.&lt;/p&gt;  &lt;p align="justify"&gt;¿Os dais cuenta lo complejo que es algo que asumimos de forma inconsciente como trivial? Pues no todo termina ahí, sino que es ahora el depurador el que debe meter las garras dentro de la aplicación defectuosa, insertándose en su espacio de direcciones de alguna manera.&lt;/p&gt;  &lt;p align="justify"&gt;Para finalizar, comentaros que esto no es más que un resumen de los capítulos 23, 24 y 25 de &lt;i&gt;&lt;a href="http://www.microsoft.com/learning/en/us/book.aspx?ID=11241&amp;amp;locale=en-us"&gt;Windows via C/C++&lt;/a&gt;&lt;/i&gt;, quinta edición.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=160776" width="1" height="1"&gt;</content><author><name>RFOG</name><uri>http://geeks.ms/members/RFOG/default.aspx</uri></author><category term="c++" scheme="http://geeks.ms/blogs/rfog/archive/tags/c_2B002B00_/default.aspx" /><category term="windows" scheme="http://geeks.ms/blogs/rfog/archive/tags/windows/default.aspx" /><category term="Visual Studio" scheme="http://geeks.ms/blogs/rfog/archive/tags/Visual+Studio/default.aspx" /><category term="vista" scheme="http://geeks.ms/blogs/rfog/archive/tags/vista/default.aspx" /><category term="hardware" scheme="http://geeks.ms/blogs/rfog/archive/tags/hardware/default.aspx" /><category term="libros" scheme="http://geeks.ms/blogs/rfog/archive/tags/libros/default.aspx" /><category term="lenguajes" scheme="http://geeks.ms/blogs/rfog/archive/tags/lenguajes/default.aspx" /><category term="Win32" scheme="http://geeks.ms/blogs/rfog/archive/tags/Win32/default.aspx" /><category term="Windows 7" scheme="http://geeks.ms/blogs/rfog/archive/tags/Windows+7/default.aspx" /></entry><entry><title>Quis custodiet ipsos custodes?</title><link rel="alternate" type="text/html" href="/blogs/rfog/archive/2009/11/15/quis-custodiet-ipsos-custodes.aspx" /><id>/blogs/rfog/archive/2009/11/15/quis-custodiet-ipsos-custodes.aspx</id><published>2009-11-15T11:38:00Z</published><updated>2009-11-15T11:38:00Z</updated><content type="html">&lt;p align="justify"&gt;No, no me he vuelto loco (en todo caso ya lo estoy), ni me ha dado por aprender lat&amp;iacute;n (ya tuve bastante de eso en el instituto), ni me he puesto a estudiar &amp;eacute;tica o filosof&amp;iacute;a&amp;hellip; Bueno, algo de &amp;eacute;tica s&amp;iacute;. Para los que no lo sep&amp;aacute;is, es una frase que aparece en una s&amp;aacute;tira de Juvenal, un escritor romano y que, traducido al castellano, significa &amp;ldquo;&amp;iquest;Qui&amp;eacute;n vigilar&amp;aacute; a los vigilantes?&amp;rdquo;.&lt;/p&gt;
&lt;p align="justify"&gt;Todo esto viene a cuento por lo siguiente. Sed pacientes porque creo que lo que voy a contar hoy aqu&amp;iacute; es, como poco, un bombazo, si no algo para que alg&amp;uacute;n juez act&amp;uacute;e de oficio. Pero comencemos por el principio.&lt;/p&gt;
&lt;p align="justify"&gt;Todos conoc&amp;eacute;is la campa&amp;ntilde;a de Tractis sobre el DNIe. Por dos euros, destinados a los gastos de env&amp;iacute;o, puedes recibir en casa un lector de tarjetas inteligentes destinado a operar con el DNIe. Ni trampa ni cart&amp;oacute;n: te suscribes y a los pocos d&amp;iacute;as recibes tu lector, aunque en mi caso los &lt;i&gt;pocos d&amp;iacute;as&lt;/i&gt; han sido como dos meses, pero s&amp;eacute; de gente que lo ha recibido en un par de semanas.&lt;/p&gt;
&lt;p align="justify"&gt;Adem&amp;aacute;s, el cacharrito funciona de cojones, o al menos se instala sin necesidad de drivers extras. Lo enchufas y listo, a funcionar. No he probado sus bondades porque no tengo DNIe, de hecho pens&amp;eacute; en conseguirlo s&amp;oacute;lo para poder jugar con &amp;eacute;l, pero a vista de lo que me ha pasado, intentar&amp;eacute; usarlo (el DNIe) lo menos posible&amp;hellip;&lt;/p&gt;
&lt;p align="justify"&gt;Si sigues las instrucciones, el siguiente paso es instalar el certificado digital y el software anexo de la Polic&amp;iacute;a, que se debe bajar de la propia &lt;a href="http://www.dnie.es"&gt;web&lt;/a&gt;. Lo bajas, lo instalas y listo, a funcionar.&lt;/p&gt;
&lt;p align="justify"&gt;Vale, ahora cambiemos de registro.&lt;/p&gt;
&lt;p align="justify"&gt;&amp;iquest;Qui&amp;eacute;n de los que lee esto no utiliza Visual Studio en alguno de sus colores? Pues eso, para muchos es &lt;i&gt;la herramienta&lt;/i&gt; con la que se gana las habas. Y todos sabemos que el Visual Studio es muy pejigueras con algunas cosas, y que sin comerlo ni beberlo puede empezar a hacerte cosas raras y a funcionar, cuando menos, &lt;i&gt;raro&lt;/i&gt;. Echemos al mejunje una sensible ca&amp;iacute;da del rendimiento general de tu ordenador.&lt;/p&gt;
&lt;p align="justify"&gt;Je, je, algunos ya sab&amp;eacute;is por d&amp;oacute;nde voy. Pero dejad que me regodee un poco en la situaci&amp;oacute;n. El ordenador va sensiblemente m&amp;aacute;s lento, sufre &lt;i&gt;enganches&lt;/i&gt; en los accesos a disco, y encima el Visual Studio te muestra errores como &lt;i&gt;&amp;ldquo;All pipe instances are busy&amp;rdquo;&lt;/i&gt;, errores que no has visto en tu miserable vida&amp;hellip;&lt;/p&gt;
&lt;p align="justify"&gt;As&amp;iacute; que uno se coge el &lt;i&gt;Process Explorer&lt;/i&gt;, que si no existiera habr&amp;iacute;a que inventarlo, y le da por inspeccionar el Visual Studio. A la primera, directa en los dientes. Os dejo una captura:&lt;/p&gt;
&lt;p align="justify"&gt;&lt;img height="643" width="526" src="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rfog/image_5F00_756F58DB.png" alt="image" border="0" title="image" style="border-bottom:0px;border-left:0px;display:inline;border-top:0px;border-right:0px;" /&gt; &lt;/p&gt;
&lt;p align="justify"&gt;Fijaros en la l&amp;iacute;nea seleccionada, y en el delta de consumo de ciclos&amp;hellip; &lt;/p&gt;
&lt;p align="center"&gt;&lt;b&gt;&lt;span style="text-decoration:underline;"&gt;&amp;iquest;Qu&amp;eacute; cojones hace esa DLL ah&amp;iacute; insertada?&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p align="justify"&gt;Y encima consumiendo un 60% del tiempo de proceso de Visual Studio. Luego uno se pone a mirar otros procesos, como el antivirus, el Messenger&amp;hellip; y en todos est&amp;aacute;. Bueno, todos no, s&amp;oacute;lo algunos. S&amp;oacute;lo aquellos &lt;b&gt;interesantes&lt;/b&gt;. Fijaros donde pone &lt;i&gt;State&lt;/i&gt;: WrLpcReply. Es una funci&amp;oacute;n del Kernel encargada de comunicaciones inter-procesos&amp;hellip; y si matamos ese proceso dentro de esa DLL no ocurre nada, Visual Studio sigue funcionando igual &amp;ndash;de mal-, pero igual&amp;hellip;&lt;/p&gt;
&lt;p align="justify"&gt;La verdad es que no tuve ganas de seguir. Desinstal&amp;eacute; el certificado, pero como no me f&amp;iacute;o un pelo, hice una instalaci&amp;oacute;n &lt;i&gt;limpia&lt;/i&gt;: apagar del bot&amp;oacute;n de atr&amp;aacute;s de la fuente. Lanzar una instalaci&amp;oacute;n formateando discos, apagar a medio instalar. Volver a lanzar otra, dejando los discos sin particiones. Apagar. Y entonces instalar de nuevo. As&amp;iacute; evitamos que se nos queden &lt;i&gt;regalitos&lt;/i&gt; en el ordenador.&lt;/p&gt;
&lt;p align="justify"&gt;No tengo nada que ocultar, pero tampoco nada que mostrar.&lt;/p&gt;
&lt;p align="justify"&gt;Las preguntas abiertas para que alguien las responda son:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;div align="justify"&gt;&amp;iquest;Qu&amp;eacute; necesidad tiene el DNIe de insertarse en el antivirus, el Messenger o el Visual Studio?&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;div align="justify"&gt;&amp;iquest;Es un error de programaci&amp;oacute;n y esa DLL deb&amp;iacute;a insertarse en otro lado y los habituales programadores chapuceros han metido la pata?&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;div align="justify"&gt;&amp;iquest;Por qu&amp;eacute; ha de consumir esa DLL tanto tiempo de proceso? Un 60% m&amp;aacute;s del normal por aplicaci&amp;oacute;n interceptada. Inaceptable.&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;div align="justify"&gt;&amp;iquest;Nos quiere espiar el Estado?&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=160521" width="1" height="1"&gt;</content><author><name>RFOG</name><uri>http://geeks.ms/members/RFOG/default.aspx</uri></author><category term="delito" scheme="http://geeks.ms/blogs/rfog/archive/tags/delito/default.aspx" /><category term="criptograf&amp;#237;a y criptolog&amp;#237;a" scheme="http://geeks.ms/blogs/rfog/archive/tags/criptograf_26002300_237_3B00_a+y+criptolog_26002300_237_3B00_a/default.aspx" /></entry></feed>