Desarrollar bajo Linux y no morir en el intento (IV). Resumen y plataforma cruzada

Tras varios días trabajando con linux, y normalmente realizando tareas previas al propio desarrollo, he llegado a la conclusión de que este entorno, pese a las versiones y revisiones habidas y por haber, se encuentra verde, muy verde en cuanto a usabilidad y a facilitar las tareas de desarrollo.


Voy a resumir una serie de problemas sin resolver y luego explicaré mis pinitos en la instalación de un compilador para arm.


Bugs sin resolver



  1. Los teclados Microsoft no funcionan bien (hay teclas muertas).

  2. KDE tiene una buena cantidad de ellos, todavía pendientes. Entre los que me afectan personalmente, están:


    1. Cada programa tiene una combinación de teclas diferente para hacer tareas comunes, y en general las operaciones habituales tienen combinaciones complejas y en las más raras las combinaciones son más sencillas, y cuando las inviertes, generalmente la nueva combinación no funciona bien.

    2. Algunos programas desaparecen misteriosamente sin dejar rastro ni logs ni nada, a veces te sale la pantalla del error, y otras, simplemente, desaparece. Entre ellas destaca el K3b, programa destinado a la grabación de CDs y DVDs.

    3. Aunque el DCOP es toda una gozada en cuanto a envío de mensajes y control de aplicaciones, todavía está muy verde en el sentido de que, por ejemplo, las teclas multimedia se pueden asignar a una aplicación, pero no a la que en este momento se encuentre activa, de forma que en ese caso te tienes que casar con un reproductor de medios en concreto.

    4. Otros programas, pese a tener miles de opciones a cual más potente y bonita, son bastante deficientes. Ejemplo es el KNode, que no permite bajar cabeceras y cuerpos a una vez, de forma que en los servidores de noticias lentos es toda una odisea esperar y esperar mientras se baja el mensaje siguiente. Y el Akregator, por ejemplo, repite RSS por un tubo. El Konqueror guarda mal algunas claves de acceso (prueba con www.ogame.com.es). El sistema de cuentas/identidades/servidores del Kmail es una castaña, para cada cuenta tienes que configurar lo mismo en tres sitios diferentes…

  3. CUPS. Mejor no digo nada… Unas veces funciona, otras no. Unas veces te imprime una página con una calidad acojonante aplicando filtros y más filtros, y otras un simple texto se va a la cuarta dimensión. En fin.

  4. KDevelop. ¿Dónde está el equivalente del IntelliSense? Y la búsqueda integrada, je, la búsqueda integrada. Hemos vuelto a los tiempos del MS-DOS con poco más…

En fin, que hay muchas deficiencias y elementos por mejorar si quieren entrar en el mundo del escritorio.


Plataforma Cruzada


Ahora empezamos con lo interesante de verdad.


Voy a desarrollar para una placa ARMV9, un chip de Textas Instruments que ya he probado bajo Windows con unas características muy buenas, veremos cómo va con Linux.


El primer paso consiste en instalar un compilador de plataforma cruzada, lo ideal sería recompilar el gcc que tienes como compilador de sistema, pero eso quizás lo haga cuando la placa ya arranque y funcione, que va a costar. El motivo no es otro que asegurarme de que el compilador va a generar el código correcto y cuando las cosas no funcionen, lo hagan porque es mi código el que está mal y no el propio compilador…


Esto puede parecer ciertamente presuntuoso, pero gato escaldado del agua fŕia huye, y ya tuve mis tejemanejes con el gcc y los ColdFire y otros Motorola 68xxx, así que mejor vale prevenir que curar.


Bueno, como iba diciendo, el primer paso es instalar el compilador certificado… Hecho, en /usr/local/arm todos los binarios, y en /opt/buildroot has herramientas necesarias para crear el propio compilador… Como prueba de mi sistema, he intentado regenerarlo y no he podido por errores en el código fuente (más que nada, incompatibilidades entre mi 4.1.1 y el 3.2.1 del arm). Añado las líneas al path y listo.


Ahora toca bajar e instalar el toolchain y generar un linux que pueda meter en la placa… Tras descomprimir los 180 megas en el directorio src local a mi cuenta… fallamos al compilar porque se intentan cambiar los permisos de ciertos ficheros locales…


Empezamos bien, muy bien. ¿A santo de qué eso de cambiar permisos a los ficheros? Parece ser que quiere hacerlos root para luego pasarlos a una imagen binaria, que será la que se cargará en la placa… Un “su” y un “source .bashrc” solucionan el problema… para entrar en otro… El redboot con compila, me dice que “tail: cannot open `+2′ for reading: No such file or directory”…


De momento en eso estoy.

Desarrollar bajo Linux y no morir en el intento (III). CUPS y la cámara WEB, amén del Skype.

CUPS es mi Némesis o, como diría mi amigo Juan, mi “mosca cojonera, aaaaaay”. Y es que no tengo suerte con este software bajo Linux. Nunca he conseguido que funcionara bien del todo.

Ahora el problema era sencillo: pese a haber dado de alta correctamente mi HP 1010 láser, los documentos impresos iban a la cuarta dimensión, o generaban el error de client-not-nosequé. Y un log configurado como nivel debu2 no me daba ninguna pista, todo lo que el sistema escribía en ese log era normal… En fin.

 En un reinicio, ya ni siquiera se cargaba el servicio, diciendome algo de un error 15. Eso fue ayer. Hoy han publicado una nueva versión que, parece ser, funciona. La he reinstalado sobreescribiendo los ficheros de configuración, he vuelto a agregar la impresora y, de momento, funciona.

Veremos lo que dura, porque otras veces he observado el mismo comportamiento y cuando he ido a imprimir… no funcionaba y he tenido de reiniciar en Windows para poder hacerlo…

Hacer funcionar la cámara Web, una Genus GE111, también, cómo no, ha resultado toda una odisea inenarrable. Una rápida búsqueda por Internet me ha dicho que mi driver es el spca5xx y que no está incluído en el kernel, sino que es necesario parchearlo… Pero mi Gentoo lo tiene como paquete independiente y símplemente con un

emerge spca5xx

he podido instalar el driver y cargarlo en el núcleo… para descubrir que me afecta el bug del ancho de banda. Este bug, presente en algunas configuraciones, hace que el driver no pueda asignar bien el ancho de banda dentro del USB (cosa que he descubierto, claro está, navegando por Internet).

Hay tres soluciones, dos de ellas sencillas que no me han funcionado y la tercera, parchear el parche. Así que, igual que con el módulo PyQt explicado en la primera entrada de esta serie, he tenido que colocar una nueva versión en el overlay de mi Portage, subir una revisión, modificar el fichero ebuild para que aplique el parche, y actualizar el módulo. Y por supuesto reiniciar linux para que cargue el nuevo módulo, pues no lo tengo compilado con la posibilidad de descargarlos.

Y de momento funciona… mejor que en Windows.

El puto Skype es harina de otro costal. Tras muchas horas mirando aquí y allá, no tengo audio con él porque a la gente que lo hace no le sale de los ejem recompilarlo para 64 bits. Y es que el Skype, que tenemos a nivel corporativo como aplicación de videoconferencia, no es trigo limpio; se trata de un sistema autoencriptado y con código automodificable que al parecer no compila bien bajo 64 bits… 

 

Desarrollar bajo Linux y no morir en el intento (II). Esas teclas multimedia que no funcionan

Otra tarea pendiente y que he solucionado a medias consiste en mi Microsoft Wireless Natural Multimedia Keyboard (sí, esos partidos) y su ratón correspondiente. Para decirlo con pocas palabras, simplemente hay que decir que bajo Linux no funciona.

No funciona conectado al puerto PS/2 porque genera una serie de texto basura como consecuencia de lo que yo considero es un bug del núcleo 2.6, pues no contempla las 255 teclas, pero no tengo ganas de meterme en líos. Lo curioso es que conectado mediante USB no presenta ese problema.

Este teclado tiene varias teclas completamente muertas, es decir, que el kernel de linux es incapaz de ver, como la de Messenger, la de Cerrar Sesión o la de Suspender. Pero hay otras que sí que ve pero el sistema se encuentra incapaz de remapear convenientemente.

Y son esas las que vamos a forzar a que funcionen y tengan un cometido. No es necesario decirle a las X qué modelo de teclado tenemos, pero si se lo decimos, algunas de esas teclas ya estarán auto asignadas. Por ello, en mi xorg.conf tengo la línea

Option “XkbModel” “microsoft”

El siguiente paso es localizar los keycodes de dichas teclas. Para ello ejecutamos en una consola el programa “xev”. Si no lo tenemos, lo instalamos mediante

emerge xev

Mientras este programa tenga el foco, nos capturará las teclas y nos dará su código de tecla. Entre todo el texto  aparecerá algo como

keycode 240

Eso es lo que necesitamos. El código 240 se corresponde con la tecla de “Mis Documentos” en mi teclado, pero sin embargo la de “Mis Imágenes” no genera ningún código, por lo que no podremos usarla para nada.

Hace tiempo estuve mirando el código fuente del núcleo de linux respecto a este tema, y vi alguna cosa rara pero no me atreví a tocar nada. Lo curioso del tema es que con un núcleo 2.4 funcionan todas, pero con uno 2.6 no, así que me reitero en lo del bug.

El siguiente paso es buscar teclas no asignadas para remapear. Para ello abrimos el fichero /usr/include/X11/keysymdef.h y allí tenemos todos los valores disponibles. En mi caso, y dado que mi teclado sólo llega al F12, he elegido remapear de la F35 hacia abajo.

Remapear una tecla en linux es sencillo: ejecutamos

xmodmap -e ‘keycode <code>=<keyname>’

para asignar un nombre a una tecla que no lo tiene. Por ello, si ejecutamos

xmodmap -e ‘keycode 240=F35’

estaremos diciendo a Linux que la tecla “Mis Documentos” es F35. Y F35 es una tecla válida para asignar allá donde queramos. 

Y ahora viene el truco del almendruco, al menos para el KDE. Si tuviéramos que ejecutar esa línea de comandos para cada tecla y cada vez que entremos en el KDE, sería un absurdo, por lo que creamos un fichero de texto con permisos de ejecución con el nombre que queramos y lo situamos en

.kde/Autostart

y dentro de ese fichero colocamos todas nuestras asignaciones, más o menos así:

#! /bin/sh
xmodmap -e ‘keycode 130=F35’
xmodmap -e ‘keycode 129=F34’

De este modo, cada vez que iniciemos KDE se nos remapearán esas teclas y podremos usarlas dentro del entorno. Evidentemente, hay más lugares en donde colocar un script para que se autolance, pero en mi caso me vale así.

Otra cosa que debería hacer es reasignar los dos botones laterales del ratón -lo ideal es que se mapearan en combinaciones de teclas-, pero aparte de reordenarlos y de asignar los de la rueda, no he visto nada… Así que si alguien sabe cómo hacerlo, que por favor me lo diga… 

 

Desarrollar bajo Linux y no morir en el intento (I). Elegir distro y compartir particiones NTFS

No era mi intención iniciar otra serie de entradas sobre el tema de arriba, pero considero que puede resultar interesante, y es en lo que estoy ahorita mismo.

Tras terminar de actualizar nuestra placa con Windows CE, nos surge la obligación de realizar los mismos pasos con Linux, ya que varios de nuestros clientes así nos lo exigen.

No es que esté muy contento con ello, porque por experiencia propia sobrevivir bajo este sistema operativo es toda una odisea -muy a persar de lo que digan los fundamentalistas linuxeros-, principalmente porque para hacer cualquier cosa necesitas leerte diez mil documentos, trastear durante dos horas y al final, si hay suerte, te funcionará. O no.

Para mi va a ser toda una aventura, pues será la primera vez que voy a implentar un sistema embebido que no es un PC y que va a ejecutar Linux en sus tripas.

La primera decisión es qué distribución instalar. Todas las distros populares adolecen del mismo problema: cargan todos los módulos del núcleo, son lentísimas a la hora de cargarse y cuando te sales de lo políticamente correcto no hay asistente y tienes que pelearte con los miles de ficheros de texto.

Por eso he elegido una Gentoo, porque yo lo valgo, porque si uno elige Linux ha de elegir lo mejor y porque me siento cómodo con ella. Además, entro a formar parte del selecto grupo de la gentooza, y cuando me surga un problema, voy a saber dónde tocar, pues asistentes tiene pocos.

Compilar una Gentoo desde un estado 3 es casi una bagatela en un AMD64 X2 con 2 Gb de RAM, eso se come el código fuente a espuertas; tardó apenas cuatro horas a compilar el KDE completo junto al KOffice, KDevelop y KDESdk.

El primer problema surge con los formatos de partición. Mi Windows XP tiene NTFS y mi Gentoo, reiserfs. Y debo por lo menos ver las particiones NTFS desde Linux.

El Kernel 2.6.xx trae soporte de serie para montar particiones NTFS de sólo lectura (También lo trae para escribir en ellas, aunque ni borracho se me ocurriría).

Pero sería estupendo si pudiera escribir en NTFS. Por ejemplo, todo el código fuente de la placa colgaría de las mismas ramas que todo mi código fuente Windows, podría utilizar el Opera como lector de correo y news compartido con Windows (Uitiliza el mismo formato de ficheros).

Así que me lío la manta a la cabeza y… descubro ntfs-3g, un parche al kernel y paquete que permite la escritura sobre NTFS sin problemas… en un sistema x86. El autor de la herramienta dice que no puede probar sobre un sistema de 64 bits porque no tiene, pero a la gente que lo ha hecho le ha ido bien.

Efectivamente, funciona de cine, de momento tengo el Opera compartido y no he observado nada extraño.

Para instalar este soporte en una Gentoo es necesario lo primero de todo desenmascarar el paquete ntfs3g y fuse, por lo que hay que añadir estas dos líneas en /etc/portage/package.keywords:

sys-fs/ntfs3g ~amd64
sys-fs/fuse ~amd64

y luego realizar un “emerge ntfs3g”.

¿Sencillo?

Si hubiera funcionado, sí, pero no funciona.

Estos paquetes dependen de PyQt que presenta un bug que impide compilarlo con la biblioteca glib instalada por defecto y de momento no tiene solución, aunque sí rodeo.

Vamos allá. Tenemos que enmascarar la versión actual, la 3.14.1-r2. Pare ello añadimos la línea

<=dev-python/PyQt-3.14.1-r2

al fichero /etc/portage/package.mask

Pero así no podemos compilar el proyecto. Tenemos que hacernos un “portage overlay”, o sea, crearnos una rama interna del Portage, copiar el paquete y subir una versión, cambiando una serie de cosas en sus ficheros de paquetes.

Primero creamos la rama de carpetas /usr/local/portage/dev-python/PyQt y copiamos todo el contiendo de /usr/portage/dev-python/PyQt. Posteriormente copiamos el fichero PyQt-3.14.1-r2.ebuild como PyQt-3.14.1-r3.ebuild, lo editamos y quitamos la línea del parche de compatibilidad. Luego hacemos un digest sobre el propio fichero.

Pero tenemos que decirle al Portage que tenemos nuestra rama de portage personalizada. Para ello abrimos el fichero /etc/make.conf y añadimos el texto “PORTDIR_OVERLAY=/usr/local/portage” sin las comillas.

Ahora, cuando el sistema pida compilar el PyQt verá que hay una versión superor a las enmascaradas en el repositorio local, y usará ese paquete. Y cuando se actualice y se solucione e bug, como poco se presentará la versión r3 si no una superior, y entonces el sistema actualizará la nueva, a no ser que ésta presente el mismo bug y tengamos que repetir el proceso. 

¿Veis lo que quiero decir con lo de sobrevivir?

Seguimos.

Ahora sí que podemos instalar el paquete adecuado. Ya solo nos queda modificar el fstab con el nuevo sistema de ficheros

/dev/partición /punto_montaje ntfs-3g auto,user,uid=1000,rw 0 0

y actualizar el listado de módulos con update_modules. La pega es que cada vez que recompilemos el núcleo debemos regenerar dicho paquete.

Y ahora viene el publicar este post. El Opera se arma la picha un lío con los campos de edición y hace unos desbarajustes de cojones. El Konqueror no entiende el login de Geeks.ms, por lo que mientras escribo este texto en el Kate, compilo el Firefox 2.0, que también he tenido que poner en package.keywords.

Y ya es hora de publicar el post, pero antes tengo que añadir el Firefox a la lista de menús, por lo que tengo que ejecutar el “Actualizador de Menús”… ¿Van entendiendo?

Tengo que copiar el texto desde el Kate, y en el proceso se pierde el formato… con lo que tengo que volver a meter todos los párrafos y las indentaciones y, finalmente, aquí está el post.

Mañana hablaremos sobre cómo hacer funcionar las teclas multimedia… cuando estas no funcionan.
 

Windows CE (I). Presentación

Llevo como tres meses dándole caña al Windows CE 5.0, principalmente como ayuda a uno de nuestros partners tecnológicos, ya que se encuentran desbordados de trabajo y nuestros clientes nos exigen/quieren ciertas actualizaciones y mejoras al desarrollo base, no de las bibliotecas ofrecidas, sino de la propia plataforma y del modo de desarrollar, que ciertamente se abandonó en preferencia a la creación de una biblioteca de clases, puesto que el dispositivo que ahora tenemos es de los denominados no head, o sea, sin vídeo.

No es que nuestra placa no disponga de pantalla, que la tiene, sino que se ha eliminado todo lo relativo al GUI que trae Windows CE de serie y se ha sustituído por una biblioteca gráfica mucho más potente y acorde con el destino del dispositivo, al modo de las Direct X, pero con otros conceptos sobre los cuales no puedo hablar.

Esta entrada quiere ser, pues, un punto de introducción sobre Windows CE y la construcción de sistemas operativos a partir de él. Por lo tanto, comencemos por el principio.

Windows CE es un sistema operativo de tiempo real no estricto, adecuado para ser instalado en multitud de arquitecturas y microprocesadores de 32 bits, que van desde el clásio x86 hasta los modernos ARM 9, XScale, SuperH, y un largo etcétera. Y por si eso fuera poco, Windows CE está compuesto por un sistema modular que ofrece la posibilidad de incluir aquellos componentes que estimemos oportunos.

Además, el coste de la licencia básica es, si no me equivoco, de 4 dólares USA.

El Platform Builder es la herramienta con la que se construye el sistema. Disponemos de un amplísimo catálogo de componentes que podemos ir instalando en nuestro proyecto, para luego pasar a la construcción del sistema operativo en sí. La tarea a simple vista puede parecer trivial, y generalmente lo es, aunque a veces pueden presentarse problemas insospechados.

Por otro lado, el fabricante del microprocesador tiene que suministrarnos lo que se llama la BSP, que es un bloque de código fuente, así como una serie de archivos que instruyen al Platform Builder de la arquitectura y de los recursos disponibles, de forma que la conjunción de estos dos elementos constituye lo único necesario para tener rápidamente un sistema operativo específicamente construido para nuestra placa.

Evidentemente, necesitamos una placa sobre la que ejecutar dicho sistema operativo, y desde mi opinión es el punto más difícil de todos, y requiere buenos ingenieros de hardware dada la complejidad del asunto. Construir una placa para Windows CE no es tarea trivial. Consideremos que una PDA o un teléfono móvil son dos ejemplos tipo, y de hecho ambos ejecutan versiones modificadas de Windows CE, ya que los Windows Mobile no son mas que versiones modificadas de Windows CE, aunque no aparezcan en los catálogos del Platform Builder.

Un dispositivo que ejecute Windows CE permite varios modelos o formas de desarrollo, algunas de ellas casí idénticas -pero con ciertas limitaciones- a las de PC. El marco de trabajo básico es un subconjunto bastante amplio del API de Win32, y sobre él se ejecutan otras bibliotecas como las MFC y otros marcos más modernos, como las versiones Compact del -NET 1.0 y 2.0. Podemos, pues, desarrollar los siguientes tipos de aplicativos:

  • Win32 en C o C++ con el eMBedded Visual C++ o el Visual Studio 2005
  • MFC o ATL con las mismas herramientas anteriores.
  • .NET Compact Framework 1.0, en C# y VB.NET con el Visual Studio 2003
  • .NET Compact Framework 2.0, en C# y VB.NET con el Visual Studio 2005
  • Visual Basic 3.0, una versión especial de Visual Basic ahora completamente descatalogada pero que todavía se puede encontrar.

Podemos comprobar que las posibilidades de desarrollo son enormes. El autor de estas líneas ha realizado proyectos en Win32, MFC y .NET 2.0 en C#, y puede afirmar que el rendimiento, dentro de las características, es muy bueno, sobre todo con lenguajes no tan evidentes como el C#.

En una próxima entrega hablaremos de las diferencias entre programar para PC y para dispositivos embebidos.

Windows Live Mail Desktop beta…

… me vais a permitir la expresión: una p*t* mierda pinchada en un palo.


Justifiquemos:



  1. El almacén que tengo en el Outlook Express me ocupa alrededor de 500 Mb, en el WLMD: más de 1.8 Gb.

  2. El Consumo de RAM máximo del OE es de unos 200 Mb en las carpetas que más mensajes tengo, en el WLMD, je je, ¡1.4 GB de RAM!

  3. El tiempo de carga del OE de la carpeta anterior, unos 10 segundos, en el WLMD, más de tres minutos.

  4. El OE no trae publicidad, el WLMD, sí.

Creo que son razones y justificaciones suficientes para mi anterior afirmación. Diré más, el WLMD, dadas esas características, no deja de ser un cliente de Correo/Noticias de juguete.


Como sé que pululan por aquí un montón de MVPs, si tienen a bien, que hagan llegar estas consideraciones a la gente que corresponda.


P.S.: Por cierto, buen sistema de filtrado de palabrotas, xDDDDDDDDDDDDDDDD.

En busca del origami perdido…

Llevo unos días detrás de conseguirme un Origami de esos, más que nada porque yo lo valgo y me apetece y ya está.


Para quien no lo sepa, un Origami es un UMPC (Ultra Mobile Personal Computer, o como diría mi tío, realmente un Ordenador Personal, para llevar en persona). Suelen pesar menos del quilo y suelen ser bastante potentes. Estamos hablamdo de un Pentium Celeron M a un gigahercio con 512Mb de RAM y discos duros que no bajan de los 40 gigas, y sin hablar de WiFi, USB 2.0, cámara, etc…


Bueno, la verdad es que esos equipos son los portátiles del futuro, y de hecho aparecen en algunas novelas de ciencia ficción. Y sin darme cuenta es lo que yo estaba soñando hace tiempo.


Los dos modelos más normales son el Samsung Q1 y el Asus R2H, ambos con similares características y que en Europa están sobre los 1.000 euros. También hay bestias pardas, como un Fujitsu con un Core2duo que vale lo que vale, y algo como entre el Fujitsu y los otros dos.


Estos cacharros ejecutan una version especial de Windows Tablet PC especialmente diseñada para ellos, y en teoría pueden ejecutar todo el sofware normal de un PC sin problemas. Y digo en teoría más que nada por el tamaño de la pantalla, que suele ser de 7 pulgadas, aunque los hay de 9 y de más.


Y por lo que dicen, aunque sean pequeños, los equipos vuelan.


Bueno, pues como iba diciendo, llevo unos días detrás de conseguirme uno, mirando aquí y allá, y al final este mediodía me he decidido. Pero como es un producto caro, prefiero echarle un vistazo en persona…


Para ello, después de comer me he bajado al Media Markt de Alicante… Tenían uno y lo vendieron ayer. Recibirán 16 para dentro de una o dos semanas…


Como el Carrefús me pilla al lado, me he dado una vuelta… Joder, ni saben lo que es ni que existe. Eso sí, la chica que me a atendido, todo un bombón en simpatía y buen rollo.


Luego he ido al Corte Maltés, en la otra punta de Alicante. Da gusto ir por Alicante un sábado por la tarde si no es por el centro. Está todo vacío, y hay sitio para aparcar casi donde quieras… menos en el centro. Me lo he pasado en grande viendo a toda la colla inútiles intentando aparcar en los Cortes Malteses y cercanías. ¿Realmente son tan pavos? A quinientos metros de allí, sitio por un tubo.


En fin, que el menda, que yo no soy tonto (by MM), ha aterrizado su buga un poco más allá del centro, dejando que quedara el lugar a donde iba hacia arriba (luego, cuando vuelvas, sobre todo si vas cargado, lo agradeces).


¿Os lo imagináis? Pues eso, Asus no tocan, Samsung sí, pero no tienen y reciben veinte el 4 de diciembre… para todo Levante.


Bueno, queda el último de todos, la Fnac, aunque en su Web no dicen nada, claro, y no dicen nada porque no tienen. Reciben próximamente 13… para toda España.


Aissssss. Cagontó, que diría el sargento Arensivia.


¿Cómo cojones quieren vender algo si no tienen cuando vas a comprarlo?


Al final, la primera idea es la que vale. El día veinte se va una semana mi jefe a los Estardos Tullidos, ya lo he comentado con él, que vaya a la tienda de la esquina, y que compre dos, uno para él y otro para mi. Y que se jodan El Corte Inglés, la FNAC, el Media Markt, los importadores y los distribuidores nacionales. Y yo me ganaré unos 300 euros por la diferencia de precio. Y si no que se espabilen.


PS: Ya sé que puedo comprar a través de tienda online, pero quería verlo antes, y a mismo tiempo de espera prefiero comprarlo fuera y ahorrarme una pasta, o lo mismo por el mismo precio aquí me compro el Fujitsu Core2duo allí.

Barras de herramientas que se guardan en ficheros INI

Recuperada y explicado en la entrada anterior el funcionamiento de mi implementación de los ficheros de texto tipo INI, ahora voy a comentar lo que motivó esa entrada.


Las aplicaciones típicas de Windows tienen barras de herramientas, barras de menús, y si quieres que tu aplicación sea mínimanente interesante, tienes que implementarlas y permitir su personalización, o al menos guardar entre sesiones las posiciones de las mismas. Personalmente pienso que es una chorrada todo ese tipo de cosas en un programa, pero a veces son necesarias por motivos de espacio u organización.


El .NET Framework 2.0 provee de forma bastante sencilla la facultad de tener elementos acoplables casi de cualquier tipo, y de eso nos vamos a aprovechar. Primero debemos soltar en nuestra ficha un componente llamado ToolStripContainer, y le cambiamos la propiedad Dock al valor Fill, que se puede hacer directamente desde la pestaña que tiene el componente como tareas coumunes. También podemos activar/desactivar en qué lados se va a permitir el acople. El resto es muy sencillo: añadir las barras y los componentes que queramos.


Cuando lancemos nuestra aplicación, los elementos aparecerán allí donde se hayan encajado durante el diseño, y permitirán ser movidos de forma sencilla por todod los laterales de la ficha. Pero cuando cerremos nuestra aplicación los cambios se perderán…


¿Cómo guardar el estado de las posiciones? Una solución sería utilizar el sistema de Config del propio .NET, pero hay que currarse a mano todas las variables, otra utilizar los flujos binarios o xml para guardarla. En este último caso ignoro si se puede salvar toda la estructura de la ficha, pero lo dudo. Además, son elementos secuenciales. En ambos casos no son soluciones generales, sino particulares, con lo que tenemos que repetir en cada aplicación nueva o en cada cambio importante que hagamos.


¿Se puede construir un sistema general, y que encima lo pueda trastear el usuario del programa? La respuesta corta: si, pero con condiciones. La respuesta larga consiste en todo lo que sigue a partir de aquí.


Primero tenemos que echar un vistazo a cómo lo hace el propio Visual Studio, por lo que hay que inspeccionar el interior del método InitializeComponent. El asunto está clarísimo: se crean los distintos elementos, luego se van agregando a la instancia del ToolStripContainer mediante la llamada a Add del array de controles, y posteriormente se colocan en su posición mediante la asignación de la propiedad Location.


Facil, ¿no? Pues no. Fuera de InitializeComponent no funciona. Simplemente coloca las barras de herramientas donde mejor le parece al sistema, ignorando en muchos casos hasta si están unas encima de las otras. Incluso aunque dupliquemos exactamente el mismo bloque de código. Haz lo que digo pero no lo que hago.


La solución más ardua sería, una vez terminado el proyecto, y sin usar el editor visual, cambiar lo que queramos dentro de IntializeComponent, pero entonces nos estaríamos metiendo en camisa de once varas, y no es el tema, así que, como dijo mi tío Saltatrampas, si no puedes contra el enemigo, dale una patada en los bajos.


Una inspección en la ayuda sobre el componente ToolStripContainer nos muestra varias cosas interesantes. La primera de todas consiste en que dicho componente tiene cuatro instancias de ToolStripPanel llamadas TopToolStripPanel, LeftToolStripPanel, RightToolStripPanel y BottomToolStripPanel, que se corresponden a los contenedores de los cuatro laterales de la ficha. La segunda es que cada uno de estos componentes contiene a su vez un array del tipo ToolStripPanelRow llamado Rows y que como su nombre indica es una reperesentación de cuántas tiras hay en cada grupo. Y para finalizar, la propiedad Controls, dependiente de éste último, otro array que contiene, ya por fin, los controles anclados a dicho contenedor.


Vista esta estructura, pensamos que si a la hora de cerrar la ficha podemos generar una representación de la misma, luego a la hora de abrirla seremos capaces de volver a reconstruirla. Dicho y hecho, aquí está nuestra solución.


Guardar el estado es bastante sencillo, para cada uno de los ToolStripContainer recorremos todos los elementos de su propiedad Rows, y dentro de ésta todos los elementos de Controls, guardando finalmente el nombre y el Location de cada uno de ellos:



int iRows,iControls;
for(iRows=0;iRows<ts->Rows->Length;iRows++)
{
  for(iControls=0;iControls<ts->Rows[iRows]->Controls->Length;iControls++)
    ControlToConfig(prefix+“Row”+iRows.ToString()+“Control”+iControls.ToString(),ts->Rows[iRows]->Controls[iControls]);
  iniFile->WriteString(form->Name,prefix+“NumRow”+iRows.ToString()+“Control”,iControls.ToString());
}
iniFile->WriteString(form->Name,prefix+“NumRows”,iRows.ToString());


En el código de arriba, prefix representa a una cadena indicando qué parte estamos guardando (Top, Left, Right o Bottom). Un rápido vistazo al fichero INI nos indica que para cada control se guarda su posición y su nombre, y como nombre a la izuqueirda del igual, su prefijo más la fila en la que se encuentra más la palabra “Control” más el número de control (por ejemplo, Top0Control1 se corresponde al control que está en el anclaje superior de la ficha, tira 0 y es el segundo control anclado en esa tira). Con un poco de perspicacia cualquier usuario avanzado es capaz de editar el fichero a mano y cambiar los valores que considere oportunos.


Cargar el estado es algo más complejo, puesto que no debemos crear los controles, sino que estos controles ya están en la ficha, por lo que es necesario buscarlos y reasignarlos.


Hacerlo de esta forma tiene algunas ventajs sobre la opción de crear los controles por programa, puesto que podemos editarlos y modificarlos sin problemas dentro del IDE y no es necesaria acción alguna cuando se arranque la aplicación por primera vez: los controles aparecerán situados en sus posiciones por defecto, y si por alguna causa se nos corrompe el archivo de configuración, con borrarlo tendremos un sistema funcional con los valores por defecto. Está claro que podríamos guardar todos los metadatos necesarios para crear el control en cuestión, pero consideramos que esta es la mejor forma.


Otra ventaja es que este código es general, tan solo requiere la llamada a los métodos ToolbarsToConfig cuando queramos guardar el estado y a ConfigToToolbars cuando queramos recuperarlo, eso sí, hay que hacerlo cuatro veces, una por cada ToolStripPanel que tengamos activo:



void FormMain::LoadToolbars(void)
{
  WindowConfig->ConfigToToolbars(this,”Top”,m_mainToolStripContainer->TopToolStripPanel);
  WindowConfig->ConfigToToolbars(this,”Left”,m_mainToolStripContainer->LeftToolStripPanel);
  WindowConfig->ConfigToToolbars(this,”Right”,m_mainToolStripContainer->RightToolStripPanel);
  WindowConfig->ConfigToToolbars(this,”Bottom”,m_mainToolStripContainer->BottomToolStripPanel);
}
void FormMain::SaveToolbars(void)
{
  WindowConfig->ToolbarsToConfig(this,”Top”,m_mainToolStripContainer->TopToolStripPanel);
  WindowConfig->ToolbarsToConfig(this,”Left”,m_mainToolStripContainer->LeftToolStripPanel);
  WindowConfig->ToolbarsToConfig(this,”Right”,m_mainToolStripContainer->RightToolStripPanel);
  WindowConfig->ToolbarsToConfig(this,”Bottom”,m_mainToolStripContainer->BottomToolStripPanel);
}


Observamos que al método correspondiente se le pasa una referencia a la ficha actual, el prefijo y el ToolStripPanel correspondiente. Pasar un puntero a la ficha no es necesario, puesto que podríamos utilizar el método FindForm del ToolStripPanel.


Estos dos métodos ha de implementarlos el usuario en cada una de sus fichas; el código de la clase WindowConfig (que tiene más cosas aparte de las mencionadas), se puede obtener aquí.


Una de cal y otra de arena. Pese a lo comentado hasta ahora, el sistema no funciona todo lo bien que debiera. De hecho, cuando hay más de una barra de herramientas en una misma tira, sólo se respetan sus respectivas posiciones en la tira número 0; en las demás se colocan siempre como quieren. El autor considera que se trata de uno de tantos bugs de los que el .NET Framework está plagado, puesto que las pruebas que ha realizado han sido bastante exhaustivas.


Entre ellas ha visto cómo al guardar una barra de herramientas, ésta tenía una localización de (300,50) y al ser cargada esa misma barra se negaba a aceptar ese valor, quedando en (300,0), lo ha visto incluso mediante el depurador en tiempo de ejecución, intentando introducir algo diferente a cero y viendo cómo la barra se negaba a aceptarlo. Se negaba tanto estando sin enlazar a ningún contenedor, como estándolo; tan sólo lo aceptaba si estaba enlazada en la tira 0. Y desde luego, una vez en tiempo de ejecución, esa barra ha podido ser movida satisfactoriamente.


Este problema se presenta tanto en el Visual Studio 2005 como en la beta de su SP.

Ficheros INI de texto en C++/CLI

Recupero un artículo (recomiendo su lectura) ya viejo de otro de mis blogs en el que hablo de una clase que en su momento creé para trastear con ficheros INI al más puro estilo Win16.


El autor es de los clásicos, prefiere lo malo conocido a lo peor por conocer, y considera que el formato de los archivos INI es algo insuperable para guardar configuraciones. Combinado con el sistema de ficheros local por usuario de los últimos Windows (ya se sabe: C:Documents and Settings<user>Local Settings…) forman una pareja insuperable a la hora de guardar pequeñas -o no tanto- opciones.


Es por ello por lo que en su momento creó una clase llamada IniStream capaz de simular el funcionamiento desde C++/CLI de estos ficheros, con la limitación de no permitir comentarios. Aparte de lo anterior, la clase contenía un bug estúpido que devolvía siempre el valor por defecto al leer un Int32, bug que descubrió al utlizar dicha clase en una de las aplicaciones que realiza en eso que sus jefes llaman trabjo y él pasarlo en grande (por favor, no se lo digan a mis superiores o lo mismo me bajan el sueldo).


Ahora, con un nuevo proyecto personal que lleva entre manos, se ha visto obligado -o más bien ha comprendido la necesidad de tener comentarios en ficheros que la gente podría leer- a añadir el soporte para los citados. Y ahora sí que ha comprobado que la clase funciona perfectamente, porque la ha incorporado al proyecto anterior y nadie se ha quejado (¿Será porque nadie usa ya esa aplicación?, agónica duda existencial) y al nuevo y ahora sí, funciona.


Se trata simplemente de una actualización, y el código se puede descargar de aquí.


Para aquellos demasiado jóvenes que desconozcan el formato de un archivo INI, diremos que se trata de un grupo de secciones que a su vez contienen valores, y estos valores están en la forma “nombre=valor”. Un fichero podría estar compuesto así:



//Esto es un comentario
[Seccion1]
Elemento1=uno
Elemento2=dos
;Esto es otro comentario
[Seccion2]
Elemento1=1
Elemento2=2


Todo lo que no esté entre corchetes ni tenga un = de por medio se considera un comentario, al menos en mi especificación de fichero INI. Luego disponemos de métodos como



ReadString(String ^section,String ^name,String ^defValue);
WriteString(String ^section,String ^name,String ^value);


De este modo leemos un valor que se corresponda a un nombre de una sección dada, o lo escribimos. Podemos indicar una Sección por defecto si la asignamos a DefaultSection, y entonces ya no tenemos que especificar la sección en las llamadas. También podemos obtener un array con todos los nombres de todas las secciones, o todos los elementos de una de ellas, y soporta indexar mediante bucles con índice numérico y/o for each.


El funcionamiento es bastante sencillo, y utiliza genéricos CLI con diccionarios de datos. La clase contiene un diccionario de diccionarios, es decir, cada grupo de elementos de una sección dada está almacenado en un diccionario, y cada sección con su grupo en otro, de forma que podemos accecer a los datos así:



String ^value=iniStream[section][name];


Toda una gozada frente a otras formas de acceder, aunque sólo podamos leer cadenas de esta forma.

Presentación

Hola a todos.

Me llamo Rafael Ontivero, aunque en los grupos de MS soy conocido como RFOG, y en otros lugares también he usado el alias de Zephryn Xirdal.

Quiero agradercer a Rodrigo Corral el que me haya hecho un hueco aquí.

En este blog voy a ir poniendo mis elucubraciones y trabajos sobre programación, generalmente C++ y C++/CLI, aunque no descarto otros temas más o menos afines o que me afecten directamente, como el tema de las máquinas virtuales, C# o Windows CE.

Aquí solo va a haber contenidos profesionales, al que le gusten mis diatribas o mis otras inquietudes, como la ciencia ficción o la literatura en general, tiene mi otro blog.

Bueno, pues eso es todo. Pasen, vean y disfruten.