Todo lo que quisiste saber sobre las DLL y no te atreviste a preguntar (I)

Las DLL tuvieron su origen cuando se quiso compartir código común entre diferentes aplicaciones para así ahorrar algo de espacio en disco (posiblemente espacio en disquetes). Esto requirió que Windows implementara ciertos modelos de memoria bastante complicados para la época (de la historia de Unix/Linux poco sé, si la idea de compartir bibliotecas en tiempo de ejecución fue anterior o posterior –supongo que anterior, aunque vaya usté a saber-), pero era hacerlo así o limitar gravemente a Windows.

Ese modelo de memoria permitió otras cosas, como que las DLL solo pudieran tener un juego de datos para todos los programas que las usaran (con la posibilidad también de contener datos únicos para cada aplicación), ahorrando todavía más memoria. Una desventaja es que un programa maleducado podía tirar al suelo no sólo a otros que usaran una misma DLL, sino al propio Windows, y eso teniendo en cuenta que la DLL estuviera bien construida y no fuera la propia DLL la que tumbara al sistema.

Ahora las cosas son bastante diferentes, cada DLL se ejecuta en el mismo espacio de direcciones que la aplicación que la llama, de manera que ya no comparten memoria ni datos: cada aplicación tiene una instancia independiente que no afecta a otras en ejecución, por lo que el motivo principal se ha perdido y ahora cumplen otros roles no menos importantes.

Tipos de DLL

Hasta la entrada del .NET Framework, existían cuatro tipos de DLL que, dependiendo de su rol, podían contener una u otra cosa.

· DLL normal de código. Es un conjunto de funciones y funcionalidad más o menos destinada a ser utilizada por otros programas. El propio Windows está construido en base a esta característica: Las DLL kernel32.dll, gdi32.dll y user32.dll forman el núcleo del sistema operativo, al menos del subsistema de Win32/Win64.

· DLL de recursos. Como su nombre indica, sólo contienen recursos y nada de código (o el menos posible). Un recurso puede ser un bitmap, una cadena de texto o la definición de un cuadro de diálogo. Este tipo de DLL es muy útil para construir aplicaciones internacionales en las que las cadenas en cada idioma están almacenadas en una DLL diferente, de modo que cuando se carga el programa podemos indicar qué DLL de recursos cargar, teniendo así nuestra aplicación, de forma casi automática, disponible en todos los idiomas que queramos. El propio Windows lo hace así con las versiones MUI, que incluyen todos los textos y otros elementos en DLL normales pero renombradas con la extensión MUI. Usando este mismo paradigma, podemos tener soporte de temas y resulta mucho más fácil cambiar o actualizar los recursos de una aplicación.

· Contenedores COM, DCOM o ActiveX. Este tipo de DLL apareció relativamente tardíamente, aunque su utilidad es más que destacable, y más que un formato de DLL se trata de un subsistema de Windows que se apoya fuertemente en la DLL para funcionar: en general la mayoría de objetos COM se encuentran almacenados en este tipo de ficheros, si bien muchas veces se les cambia la extensión por OCX, aunque no es imprescindible.

· DLL de extensión. Aunque a primera vista podrían estar incluidas en el primer tipo, la construcción de estas necesita de ciertos cuidados especiales o nos encontraremos con serios problemas en su uso y su creación. Una DLL de extensión extiende la funcionalidad de alguna aplicación o marco de trabajo o del propio Windows.

Tras la entrada en escena del .NET Framework, los tipos de DLL se han extendido, o más bien los tipos anteriores han aumentado sus roles así como sus nombres y la división clara entre una clase y otra se ha perdido en cierta manera. En general una DLL .NET ya no se llama así, sino que se llama ensamblado y puede cumplir uno o varios roles anteriores. Los ensamblados normales ahora contienen una buena cantidad de metadatos que los convierten en un paso más allá de los contenedores COM, no suelen incluir código ensamblador sino que en su interior sólo hay instrucciones MSIL y Windows es incapaz de entenderlas sin el soporte del motor en tiempo de ejecución (runtime) de .NET.

Evidentemente, la división anterior es solo conceptual, ya que nadie nos impide tener una DLL que contenga código, recursos y extienda un marco de trabajo existente o se inserte como un servidor COM dentro de Windows. No obstante, y en general, los programadores suelen respetar la división.

Usos modernos de una DLL

Ya hemos visto algunos en el punto anterior, aunque podemos indicarlos para mayor claridad.

· Interfaz con un Driver. Muchas veces cuando tenemos que acceder a un dispositivo más o menos exótico el fabricante nos suministra una DLL que nosotros usaremos para comunicar nuestra aplicación con el dispositivo.

· Soporte de alguna funcionalidad suministrada por un tercero. Si bien también nos podría dar una biblioteca estática para enlazar con nuestra aplicación, el disponer de una DLL significa que ésta también podrá ser usada en otros lenguajes.

· Soporte de temas. Ponemos todos los recursos de una aplicación en una DLL y el hecho de cambiar de tema supone usar otra DLL con los mismos nombres y tipos de recursos pero diferentes en aspecto.

· Soporte de idiomas. Ponemos todas las cadenas de nuestra aplicación en una DLL y la cargamos en consonancia al idioma seleccionado. Aquí tenemos la desventaja de tener que cargar a mano con LoadString() todas las cadenas antes de usarlas. Por ejemplo, MFC ayuda en cierta manera a disponer de este sistema de internacionalización, y otras herramientas como C++Builder o el propio .NET las implementan de forma automática, generando y cargando la DLL adecuada en cada caso sin nuestra intervención.

· Ofrecer servicios actualizables. Esta es una gran ventaja, que utiliza el propio Windows y Visual C++ para insertar actualizaciones. Si ponemos cierta funcionalidad en una DLL, cuando queramos actualizarla sólo tendremos que cambiar dicha DLL por otra nueva que conserve el mismo interfaz público (o al menos la parte usada). Es lo que hace Microsoft con el runtime de Visual C++ cuando se produce alguna actualización de seguridad o corrección de bugs: en Windows Update nos aparece la correspondiente actualización, que sustituirá (más bien añadirá) la nueva versión al repositorio SXS.

· Modificar el comportamiento del sistema añadiendo ganchos (hooks) a Windows. Un ejemplo a esto es insertar una DLL para que actúe de filtro de teclado, dando funcionalidad a las teclas multimedia de nuestro teclado, y una variante es insertar una DLL en otro proceso para tomar el control (o permitir más funcionalidad), que es lo que hace, por ejemplo, Skype (Y no sé para qué).

· Compartir código entre aplicaciones. Aunque a fecha de hoy el ahorro de disco puede ser insignificante, disponer de DLLs con funcionalidad común puede suponer solucionar un bug o realizar algún tipo de mejora de forma simultánea en todas las aplicaciones instaladas que usen dicha DLL. Y por supuesto también está su contrapartida: estropear algo en todas.

De todos modos, esta lista sólo es una aproximación. Seguro que el lector conoce otros usos o se los puede imaginar.

Requisitos para ser una DLL "estándar"

Con esto nos referimos a los requisitos para que una DLL pueda ser utilizada por prácticamente cualquier otro lenguaje de programación, como puede ser el Visual Basic clásico, los lenguajes .NET, Cobol, Dephi, Fortran, etc., e incluso aplicaciones con soporte para ellas como Mathlab y otras.

· El interfaz de programación ha de consistir en funciones globales con el protocolo de llamada __stdcall de paso de parámetros. Cuando uno hace una llamada a función, el punto de retorno y los parámetros que vamos a usar se guardan en la pila. Dependiendo del protocolo de llamada, la limpieza de la misma corresponderá a quien llama o al llamado, así como el orden en el que los parámetros se guardan en ella también depende del protocolo. Como su nombre indica, __stdcall especifica un formato que todos los lenguajes deberían entender si quieren comunicarse con el mundo exterior. Hasta donde yo sé no existe ningún lenguaje moderno que pretenda soporte de extensiones y que no entienda el protocolo __stdcall.

· Si hay variables globales, éstas deben ser de los tipos más estándar posibles, como enteros con un tamaño prefijado. Nada de punteros ni estructuras complejas ni otros elementos dependientes de un compilador en concreto, aunque lo mejor es que no haya ningún tipo de elemento global aparte de las funciones.

· Los parámetros pasados y devueltos han der ser tipos estándar y perfectamente definidos, y debemos huir como de la peste de punteros a void y burradas similares (aunque a veces son inevitables).

· Nada de clases, ni objetos, ni funciones con extensiones no estándar (por ejemplo, paso variable de parámetros o parámetros por defecto).

· Disponer de un punto de entrada con la firma y la funcionalidad siguiente (Sacado de la MSDN, luego explicaremos esto, cualquiera de las dos firmas nos vale):

BOOL WINAPI DllMain(
HINSTANCE hinstDLL, // handle to DLL module
DWORD fdwReason, // reason for calling function
LPVOID lpReserved ); // reserved
int __stdcall DllMain(
HINSTANCE hinstDLL, // handle to DLL module
DWORD fdwReason, // reason for calling function
LPVOID lpReserved ); // reserved

No obstante, muchas de estas reglas son relajables. La mayoría de lenguajes pueden lidiar con punteros y con estructuras de datos, otros no necesitan para nada el punto de entrada, y otros también trabajan bien con el protocolo de llamada __cdecl, que es el estándar de C y C++.

Con lo que sí que no suelen poder es con las extensiones de C++ como las clases, los parámetros por defecto o variables, el protocolo de llamada __fastcall y otras extensiones que muchos compiladores de C++ suministran, como gestión de excepciones y punteros relativos.

Esto no quiere decir que no podamos usar esas cosas en nuestra DLL, que sí podemos, lo que quiere decir es que el interfaz público con el que se debe comunicar la DLL no debe tenerlos. Luego, en nuestro código, podremos usar lo que queramos siempre que no salga fuera. Si usamos excepciones deberemos capturarlas dentro de nuestra DLL y no lanzarlas fuera a no ser que sean del tipo del sistema operativo (y en ese caso tampoco es recomendable).

Aunque pueda parecer extraño, ya que la mayoría de lenguajes modernos implementan clases, las de C++ están prohibidas en la parte pública de una DLL. Eso se debe a la forma en que C++ genera el código. Cuando C++ compila una clase, genera una lista de funciones globales del tipo "MiClase@MiMetodo@&D%&", que es la forma que tiene el compilador de empaquetar toda la información sobre el tipo de la función o de la variable. Él sabe cómo se llama el método, y lo llamará de la forma adecuada dentro del código fuente, pero externamente todos esos añadidos no son estándar y suelen variar de compilador a compilador (e incluso entre versiones del mismo), por lo que si exportamos una clase para que sea vista públicamente en nuestra DLL, la DLL exportará dicho listado de funciones.

Realmente se puede hacer, pero luego tenemos que figurarnos a qué método se corresponde cada función y simular el funcionamiento del objeto desde la aplicación que esté usando la DLL a no ser que nuestra aplicación esté escrita en C++ y compilada con el mismo compilador. En ese caso podemos exportar y usar una clase (o cualquier otro tipo de elemento), pero el consumo ha de ser interno.

Y a veces nos encontramos con esta misma situación cuando usamos una DLL de un tercero: éste la ha generado y comprobado con su compilador y en su sistema, y luego el usuario final se encuentra con un batiburrillo de estructuras, punteros, punteros a void y demás zarandajas que le hacen muy difícil usarla en su sistema.

Por eso lo de las reglas.

En una próxima entrada veremos los aspectos prácticos de todo esto.

Cómo activar la conexión de red por USB en el Kindle 2 (v.2.0.3) y en el DX (y de paso tener acceso por telnet)

Un breve apunte para aquellos Kindleros hispanos: si tienes el firmware 2.0.3 del Kindle 2 o el Kindle DX, que desactivan el acceso por red mediante USB, el amigo Ebs ha publicado un Hack para volver a tenerlo, y encima de forma mucho más sencilla y configurable y sin tocar apenas el firmware original, de hecho se puede desinstalar a mano.

No olvidéis que podéis joder a base de bien vuestro Kindle. Si lo hacéis, por aquí no vengáis a quejaros.

Lo que hace el hack es crear una carpeta en la zona pública y enlazar el comando interno “usbNetwork” a uno equivalente en la carpeta añadida. Editando este fichero podemos asignarnos las IP para adecuarlo a nuestras necesidades.

Aquí el hilo: http://www.mobileread.com/forums/showthread.php?t=49350

Aquellos que tengáis un Windows de 64 bits, el driver de red por usb no se instalará, por lo que hay que bajarse el fichero http://www.davehylands.com/linux/gumstix/usbnet/linux.inf y aplicar los cambios descritos en el punto 7 de esto: http://docwiki.gumstix.org/Windows_XP_usbnet#Step_7. Luego tendremos que apuntar la instalación del driver a ese fichero (Esto está sacado de los comentarios de la entrada original sobre el hack (http://blog.fsck.com/2009/03/tethering-your-kindle.html).

¿Que por qué no soy más específico? Pues porque si no tienes los conocimientos necesarios para ello, mejor deja tranquilo tu Kindle.

 

Vídeo de introducción al MFC Feature Pack de Microsoft en Microsoft

Bueno, como podéis ver, aunque me queden un par de entradas sobre el Kindle, el RFOG sigue en la brecha de sus cosas de C++ y demás zarandajas, que fue el origen de este Blog. El que haya escrito poco sobre mis temas últimamente se debe a que he tenido mucho trabajo y he estado enormemente ocupado… ¿Qué? ¿No te lo crees? Pues yo tampoco, para serte sincero.

Esto de las ganas de escribir en el blog va y viene, y unas veces hay más y otras menos, y las más una perrería de tumbarme a leer novelicas de ciencia ficción que no os lo creeríais (o a lo mejor sí, vaya usté a saber).

Bueno, dejémonos de rollos patateros y vayamos al asunto:

Ayer Microsoft publicó en Channel 9 España un video muy chulo que he hecho sobre el Feature Pack. Es una introduccion rápida por las características del mismo, y la verdad es que me hubiera gustado profundizar más. No prometo que lo haga, pero tampoco que no… ya que por fin hay algo en MFC moderno, últil y funcional (y que encima no le he encontrado ningún bug, y eso que llevo ya dos aplicaciones hechas con él).

Bueno, pues nada, aquí está el vídeo. Que lo disfrutéis.

http://channel9.msdn.com/posts/Daniel+Garzon/C-MFC-Feature-Pack/

 

¿Qué es C++ y qué es C++/CLI?

Introducción

Suele aparecer con cierta frecuencia en los foros de ayuda cierta confusión entre C++ y C++/CLI. Hay quien pregunta algo de C++ siendo C++/CLI y viceversa, o quien intenta aplicar algo de C++/CLI a C++ (y también al revés), o simplemente se ve completamente ofuscado con el tema. En esta entrada vamos a intentar poner un poco de orden en todo esto.

C++ no es C++/CLI

C++ es el lenguaje de toda la vida, inventando por Stroustrup y que, pese al deseo de muchos, está más vivo que nunca y sigue creciendo en funcionalidades y potencia, como es el hecho de que el próximo estándar va a añadir cosas muy interesantes que veremos por aquí. Si no pasa nada, antes de fin de año estará aprobado, se llamará C++09 y sustituirá a C++03 (No, no os penséis que hay 6 versiones entre uno y otro, no, es que el estándar se llama con el año en que se aprobó –si, ya sé que no es lo óptimo pero es así).

En C++ tenemos punteros, referencias, clases, herencia, polimorfismo y todo lo clásico del lenguaje, y los últimos compiladores de Microsoft lo implementan muy bien. Es decir, con Visual C++ (la versión que sea), se puede seguir programando como hasta ahora, con MFC, con Win32 o con cualquier otra biblioteca existente (QT, wxWidgets, y un largo etcétera).

Luego tenemos la plataforma .NET, en la que C++ no puede entrar directamente ya que hay cosas que .NET no soporta, entre las que caben destacar los punteros y la herencia múltiple. No vamos a entrar en detalles de por qué eso no funciona, sino que vamos a aceptarlo como dogma (quizás en algún momento futuro me dé por explicarlo, aunque tampoco es un tema difícil en exceso).

Por lo tanto Microsoft creó un nuevo lenguaje que llamó C++/CLI[1], es decir, el C++ del CLI. Si bien en su momento fue diseñado para que fuera un lenguaje de primera clase (otra forma de decir que debía soportar todo el conjunto de .NET), con la llegada de la versión 3 del Framework C++/CLI se quedó como una herramienta avanzada de interoperabilidad entre .NET y Win32 (luego veremos más sobre esto).

Existen dos formas para acercarnos a las diferencias entre C++ y C++/CLI, o más bien se trata de dos maneras de explicar los mismos conceptos. Yo al menos no tengo clara cuál es la versión formal, si bien me aboco por la primera. Veamos en detalle estas das aproximaciones.

PRIMERA APROXIMACIÓN: C++ es un subconjunto de C++CLI

C++/CLI incluye a C++. Es decir, todo lo que se puede hacer en C++ también se puede hacer en C++/CLI, y más. Si nosotros cogemos un código fuente escrito en C++ y lo compilamos como C++/CLI obtendremos un programa completamente funcional igual que lo era compilado en C++. No vale intentar llamar a una DLL nativa como si fuera nuestro programa, ni a un fichero objeto ya compilado (no me refiero a un objeto, sino a un fichero .obj), debemos partir del código fuente, todo el código fuente.

De este modo, hemos convertido un programa C++ en otro C++/CLI que necesita el .NET Framework para funcionar pero que simplemente continua siendo, exactamente, el mismo que antes y con el mismo código fuente.

Y entonces podemos añadir código que use cosas del .NET, con ciertas limitaciones que veremos luego, pero lo que sí podemos es utilizar los nuevos conceptos de .NET, como referencias manejadas, liberación automática de memoria, genéricos y demás zarandajas.

Por lo tanto, está claro que C++ es un subconjunto de C++/CLI desde este punto de vista.

SEGUNDA APROXIMACIÓN: Son lenguajes diferentes que funcionan lado a lado

Aquí C++ tiene una parte de su sintaxis compartida con C++/CLI de igual modo que el primero la tiene con C. No obstante, son dos lenguajes completamente diferentes que no sólo pueden interactuar entre sí (como C y C++), sino que incluso pueden escribirse en un mismo código fuente, de manera que unas sentencias estarán en C++ y otras en C++/CLI.

A primera vista puede parecer extraño, pero lo cierto es que se trata de una aproximación también correcta (y lo demostraremos).

Si bien podemos compilar un programa existente como .NET, ese código no usa nada de .NET, y el código que creemos para usar .NET no se puede utilizar con el antiguo, no al menos de forma directa: no podemos tener una referencia manejada a un objeto nativo, ni un puntero nativo a una referencia manejada, no podemos obtener la dirección de un objeto manejado, y muchas otras limitaciones más.

Sin embargo, sí que hay otras cosas que podemos compartir de forma indistinta: muchos de los tipos nativos, podemos alojar un puntero nativo en una clase manejada (al revés también, pero con ciertas complicaciones adicionales), y podemos interactuar con código nativo de forma mucho más sencilla que con otros lenguajes.

RESUMIENDO, que es gerundio

Antes de entrar en otras profundidades, conviene hacer un breve resumen de lo que estamos tratando.

Hemos visto que Microsoft tiene dos lenguajes C++: el tradicional y el .NET, llamado C++/CLI. Con el primero ellos podemos construir programas tradicionales (MFC, QT, Win32, etc.). Con el segundo desarrollamos aplicaciones para .NET.

Por otro lado, podemos mezclarlos, o usarlos de forma combinada para crear aplicaciones mixtas que usen partes en Win32 o nativas y partes en .NET o manejadas.

No obstante, son lenguajes diferentes que comparten bastante sintaxis.

Rizando el rizo

Supongamos el siguiente programa, creado a partir del asistente para "Consola CLR", que es como MS llama a un programa C++/CLI en modo consola.

#include "stdafx.h"

#include <stdio.h>

using namespace System;

int main(array<System::String ^> ^args)
{
    printf("Hello World");
    Console::WriteLine("Hello World");
    return 0;
}

Si nos fijamos atentamente, es una mezcla de código nativo (la inclusión de stdio.h y la línea que contiene printf) y código puramente .NET, y si lo ejecutamos veremos cómo se imprimen ambas líneas por la consola.

Por otro lado, podemos elegir entre tres modos de generar un programa en C++/CLI: la opción por defecto es "/clr", aparte de "/clr:pure" y "/clr:safe". ¿En qué afectan a nuestro modelo? En bastantes cosas. La imagen siguiente nos localiza, dentro de las opciones del proyecto, el lugar en dónde cambiarlo:

clip_image002

La primera de ellas es que la opción "/clr:safe" no nos permite compilar código mixto; es decir, si intentamos compilar el programa de arriba con esa opción obtendremos una muy larga lista de errores en relación a la inclusión de stdio.h y del printf. Si quitamos esas dos líneas y compilamos con dicha opción nuestro programa, se ejecutará sin problemas, y si lo miramos por ejemplo con el .NET Reflector veremos que es idéntico (o casi) a cualquier otro programa equivalente escrito en, por ejemplo, C#.

"/clr:pure" nos dice que nuestro programa, aparte de acceder a código manejado, también puede tener código nativo compilado como código manejado. Y finalmente la opción por defecto nos permite, aparte de lo anterior, acceder a módulos completamente compilados como código nativo y a compilar la parte nativa como tal.

Por ejemplo, si compilamos nuestro ejemplo con cualquiera de las dos opciones reseñadas, obtenemos el siguiente código generado por el .NET Reflector:

int main(int argc, char modopt(IsSignUnspecifiedByte^)** argv)
{
    ::printf(&::?A0x67b7b245.unnamed-global-0);
    Console::WriteLine("Hello World");
    return 0;
}

Vemos cómo hacemos una llamada a la función printf, que es nativa, con una cadena también nativa y luego hacemos una llamada a WriteLine con una nueva cadena, esta vez todo código manejado.

Una primera aproximación nos dice que C++ es un subconjunto de C++/CLI ya que la llamada a printf se realiza desde código manejado, y el parámetro es la dirección de un miembro de una estructura global, o eso parece). Estamos en la primera aproximación.

Segunda vuelta al rizo

Veamos ahora el siguiente código:

#include "stdafx.h"
#include <stdio.h>

using namespace System;

void printk(const char *p)
{
    while(*p)
    putchar(*p++);
}

int main(int argc,char **argv)
{
    printk("Hello World");
    Console::WriteLine("Hello World");
    return 0;
}

Hemos cambiado poco, pero lo suficiente para ver ciertas diferencias en el código compilado resultante. Hemos añadido una función nativa que recibe un puntero a una cadena y la pone en consola.

¿Qué se imagina el lector que pasará al compilar esto tanto con "/clr" como con "/clr:pure" (recordemos que "/clr:safe" no puede contener código nativo de ningún tipo)? ¿Qué pasará con la función printk?

Veámoslo, pero esta vez con el ILDasm:

clip_image004

Da igual que lo compilemos con cualquiera de las dos opciones, de nuevo una función nativa ha sido compilada como manejada, estamos, otra vez, en el primer caso (y recordemos que .NET, junto a C#, permite punteros, algo no muy tenido en cuenta a veces).

El tercer rizo (y punto final)

Bueno, ya sólo nos queda un nuevo ejemplo de código:

#include "stdafx.h"
#include <stdio.h>

using namespace System;

#pragma unmanaged
void printk(const char *p)
{
    while(*p)
    putchar(*p++);
}
#pragma managed

int main(int argc,char **argv)
{
    printk("Hello World");
    Console::WriteLine("Hello World");
    return 0;
}

Hemos colocado nuestra función nativa bajo las directivas del preprocesador indicadas. Si ahora intentamos compilar este programa con la opción "/clr:pure", nos saltará un error diciéndonos que no podemos compilar la función printk como nativa bajo este modelo.

No obstante, si lo hacemos con "/clr", obtendremos el siguiente código para la función printk:

clip_image006

¡Ondia! No está, no hay nada… Realmente está ahí, pero al ser código nativo, ni el ILDasm ni el Reflector son capaces de verlo. Ahora nos hemos acercado un poco más a la segunda aproximación, en la que estamos viendo cómo C++ va por un lado y C++/CLI por el otro.

Sí, ya sé que es una forma un poco retorcida de verlo, pero sigamos…

Podríamos haberlo complicado un poco, compilando dos módulos independientes, uno con las opciones para C++/CLI y otro sin ellas, y haber hecho la llamada del manejado al nativo, pero ¡eso es exactamente lo que ocurría cuando hacíamos la llamada a printf!

O a cualquier otra función de Win32 o de una biblioteca de C++ nativa. Por tanto, la segunda aproximación también es completamente cierta. Alguien podría objetar que “eso pertenece a una DLL”, pero podemos compilar nuestro código con enlace estático al runtime de C y tendríamos el mismo caso: ejecutando código nativo y manejado desde un mismo ejecutable.


[1] Olvidémonos por completo de las managed extensions, haremos como si no existieran ni hubieran existido nunca jamás de los jamases J.

Kindle II: Modo debug y otros comandos chulos

Siguiendo con la serie sobre el K2, ahora me toca hablar del modo debug del mismo, pero antes comentarios que mi amigo JaviJavier ha añadido a su entrada los atajos de teclado que tiene el K2 para acelerar ciertas funciones. Como siempre, aquí.

El modo debug

El K2 tiene un modo que se ha dado en llamar modo debug y que pone al aparato en una funcionalidad extendida. Al que le pueda extrañar, es algo habitual cuando uno está finalizando un proyecto grande el tener algunas cosicas especiales para acelerar el trabajo, que es, por ejemplo, de donde vienen los trucos para acceder a niveles o desbloquear ciertos elementos de un juego. ¿O es que os creéis que los programadores se pasan 20 niveles antes de llegar al que les interesa para depurarlo? 😛

Bueno, pues el K2 se puede poner en ese modo, y de esta forma acepta una serie de comandos extendidos que nadie sabe para qué funcionan… excepto algunos, entre los que cabe destacar el modo red a través del USB…

Todos los comandos se introducen de la misma forma: en el campo de búsqueda y desde el visor de ficheros, lo que los diferencia de una búsqueda normal es que comienzan con un símbolo especial.

Comandos chulos

Para hacer una búsqueda en el visor de ficheros tan sólo hay que empezar a teclear, pero como los comandos empiezan por símbolos, primero es interesante apretar “ENTER” para que se abra la caja de búsqueda.

@time Muestra la fecha en un diálogo.

@store Realiza una búsqueda en la tienda.

@wiki ó @wikipedia Realiza una búsqueda en la Wikipedia.

@web Realiza una búsqueda en Google.

@help muestra una pantalla de ayuda en el que aparecen estos mismos comandos.

@dict Busca en el diccionario.

Hay alguno más que empieza por arroba pero no sé para qué sirven.

;dumpMessages Vuelca los mensajes del log interno a un fichero en la carpeta de documentos. Interesante para ver un seguimiento de lo que ha pasado dentro de nuestro aparato.

;debugOn Pone el nivel de log a 2 y activa los comandos ocultos.

;debugOff Pone el nivel de log a 1 (el normal) de desactiva los comandos ocultos.

Comandos ocultos

Una vez activados, tenemos toda una nueva tanda de comandos extra.

MUCHO OJO CON ESTOS COMANDOS. HAY ALGUNOS QUE NO SE SABE QUÉ HACEN, Y OTROS QUE, POR EL NOMBRE, SIGNIFICA QUE VAN A HACER COSAS PELIGROSAS.

ÚSALOS A TU ENTERA RESPONSABILIDAD.

SI EJECUTAS ALGUNO Y TU KINDLE SE ROMPE LUEGO NO VENGAS CON PEGAS.

LO DICHO.

Después de lo dicho, avisado estás. Yo aquí voy a explicar los que sé qué hacen porque los he probado:

`memInfo Muestra un cuadro de diálogo con la memoria libre y consumida.

`help Lista los comandos disponibles.

NOTA: El apóstrofe está en la penúltima posición de la línea central de la pantalla de símbolos que se abre con la tecla SYM.

Modo red a través de USB

Hay dos comandos más que, si tienes la versión 2.0.2 o inferior del firmware, cambiarán la funcionalidad del USB y lo convertirán en una conexión de red normal y corriente.

NOTA: No instales la versión 2.0.3 del firmware si quieres que esto funcione.

¿Qué puedes hacer con esto? Pues menos activarlo, todo lo que se podría hacer en USA a través de la red telefónica… Te pondrá el K2 en hora (con dos horas de retraso) y te bajará las cosas pendientes. Me comenta JaviJavier que sólo te pone en hora el K2 y sólo te deja navegar por la tienda de Amazon. Tampoco te descarga lo que tengas pendiente. Todo lo demás necesita que el aparato esté registrado, y quizás funcionara si uno se fuera a USA, lo activara y se volviera a España, pero esto último sólo es una suposición.

Interesante, ¿no?

Pasos a seguir:

1. Pulsa ENTER y teclea ;debugOn y vuelve a pulsar ENTER para activar el modo.

2. Pulsa ENTER y teclea `usbNetwork y vuelve a pulsar ENTER.

3. Pulsta ENTER y teclea `usbQa y vuelve a pulsar ENTER.

Ahora el USB del Kindle es una conexión de red.

Enchúfalo al PC y verás que éste te ha detectado un nuevo interfaz de RED. Tienes que poner la IP 192.168.15.200.

Una vez hecho eso puedes hacer ping al K2 y éste te responderá.

El siguiente paso es compartir tu conexión de internet para que esté disponible en el K2.

Una vez hecho esto, desde el menú del K2 podrás conectarte a internet como si estuvieras usando el modem de Whispernet y navegar por la tienda de Amazon. La entrada original en inglés que explica esto está aquí, y si no sabes cómo compartir una conexión o poner una IP, seguro que encuentras en internet cómo hacerlo.

Chulo, ¿no?

Los hacks del Kindle 2

Veo bastante complicado que yo pueda crear hacks para él ya que en la versión del firmware que tengo, la 2.0.3, el soporte de red por USB ha sido eliminado, con lo que la facilidad para ver el interior del aparato se pierde por completo.

No obstante sé de gente que ha podido restaurarla y sé de gente que tiene control completo del K2, pero no sueltan prenda. Yo tengo prevista una vía de ataque para reactivarlo que creo podría funcionar… pero prefiero esperar un tiempo a ver si se publica una solución.

Así que de momento, y mientras JaviJavier se ocupa de generar una lista de todos los atajos de teclados y otras zarandajas, yo voy aquí a explicar los tres hacks que hay, a fecha de hoy, para el K2.

Instalar un hack y desenladrillamiento (por si acaso)

Ya lo dije en la entrada anterior: para instalarlo sólo es necesario colocar el fichero .BIN que nos suministren en la carpeta raíz del K2, ir a “Settings”, a través del menú y una vez allí, de nuevo con el menú, elegir “Update your Kindle”. Nos pedirá confirmación y una vez aceptado, iniciará la actualización. Cuando se reinicie, ya está, el hack ha sido aplicado.

A veces puede ocurrir que se quede reiniciándose de forma infinita. No problemo. En uno de esos reinicios mantenemos apretada la tecla “Home”. Una vez allí, pulsamos R y debería reiniciarse normalmente. Y si continua reiniciándose, volvemos a esa pantalla y lo conectamos por USB. Una vez que nos reconozca la unidad, borramos el fichero de actualización que esté fallando y reiniciamos.

Cambiar la fuente (y mejorar el contraste)

El hack por antonomasia es este. Ya hemos visto que nuestro K2 tiene poco contraste. Los expertos dicen que se debe a que el K2 tiene más niveles de grises y por tanto, con las fuentes pequeñas (tamaño 3 o menos), el algoritmo de redondeado hace que los contornos pierdan intensidad. Yo en principio me lo creo, pero también creo que deberían de haberlo detectado y solucionado con un firmware oficial.

No obstante, con este hack podemos instalar prácticamente cualquier fuente con solo colocar el fichero adecuado… En este momento hay disponibles 17 fuentes diferentes, y organizar un nuevo parche para cambiarlas no es nada difícil ya que la infraestructura está creada.

Para obtener la fuente que nos guste, nos vamos aquí y al final del todo tenemos los ficheros para bajarnos. No obstante sería interesante que leyéramos, si sabemos inglés, la página a donde hemos apuntado.

Yo he probado la Georgia 2 y la Helvetica 2 y de momento me quedo con la primera.

OJO CON EL HACK: Tras aplicarlo, nos dejará en el raíz de nuestro K2 varios ficheros. No debemos borrarlos, ya que cuando desinstalemos el hack con UPDATE_UNINSTALL.BIN, nos harán falta para recuperar el estado del K2.

Instalar nuevas imágenes en el salvapantallas

Este no lo he probado, pero tampoco debe ir mal ya que hay mucha gente que se lo ha instalado. Si sabemos inglés lo suyo es que leamos esto, esto y esto. Básicamente el proceso es el mismo que antes: nos bajamos el hack de aquí, lo descomprimimos y colocamos el fichero .BIN en el raíz de nuestro K2 y seguimos los pasos descritos más arriba.

Tras el reinicio del K2 tendremos una carpeta nueva en system/screen_saver que contendrá todas las imágenes del salvapantallas original. Ahí pondremos las nuestras, pudiendo quitar las originales si quisiéramos. Eso sí, para que el K2 las reconozca, debemos reiniciarlo.

No he instalado este hack, así que no sé el resultado, pero por lo leído por ahí, funciona perfecto.

¿No ves la carpeta system en tu K2?

Eso sólo pasa en Windows, tienes que, desde el explorador de Windows, ir a Tools -> Folder Options -> View y desmarcar Hide protected operating system files. Tras hacer eso podremos ver la carpeta system en la unidad del K2.

Mi consejo es que una vez que hayáis visto/cambiado dicha carpeta, volváis vuestro Windows a su estado anterior, ya que dejar a la vista en Windows (sobre todo XP) ciertas carpetas que esa opción oculta puede ser MUY peligroso para los zarpas e inexpertos.

Leer PDF y EPUB (sin DRM) en el K2

Para algunos este es el hack por antonomasia, el súmmum de todo lo que existe para el K2. Personalmente pienso que es una chorrada como un castillo, pero lo que sí tengo que reconocer es que técnicamente hablando es una gran demostración de los conocimiento del chaval que lo ha hecho y demuestra un gran conocimiento interno del K2 (y entre nosotros es el que sabe cómo entrar en el K2 pero no suelta prenda).

Este hack tiene nombre y se llama Savory. Una vez instalado se queda residente en nuestro K2 y cuando detecta un fichero PDF o EPUB lo que hace es convertirlo a MOBI desde el propio K2. Una vez que lo ha hecho sustituye el primero por el segundo, y entonces ya podremos leerlo.

La única ventaja que le veo a esto es que nos ahorramos convertirlos a mano o con el programa Calibre, pero es la única, ya que encima el programa, al estar residente, consume batería y cuando esté trabajando, más todavía. Y para más inri, usa el conversor del propio Calibre.

Para instalarlo necesitamos dos ficheros. El BIN que hará de actualización y la imagen de disco que será copiada e integrada (más bien montada como un disco virtual) dentro del K2.

La entrada principal del blog del autor es esta. En ella encontrarás información sobre el hack y sobre cómo funciona, aunque hay otras entradas. La última versión cuando escribo esto es la del 4 de marzo de 2009, pero conforme vaya pasando el tiempo seguro que habrá alguna más moderna, por lo tanto lo mejor es mirar en el blog del autor.

Una vez que nos hemos bajado la imagen y la hemos descomprimido, la dejamos en el directorio raíz de nuestro K2 junto al instalador. Por lo tanto debemos tener dos ficheros: savory-image.ext3 y update-savory-0.06.bin. De todos modos es mejor que os aseguréis de si hay nuevas versiones antes de instalar estas que yo os he puesto.

Y finalmente debemos seguir los pasos que he indicado arriba del todo.

Cuando queramos desinstalar Savory deberemos dejar el desinstalador en el raíz y repetir los pasos.

Este tampoco lo he probado, pero no hay nada que indique que no vaya a funcionar.

Estos son los tres hacks que hay de momento para el K2, y de momento que yo sepa no hay nadie que esté trabajando en otros, y como el amigo FSCK o como se llame no suelta prenda, los demás estamos a dos velas (Igor se ha desentendido del K2, toda su información es válida solo para el K1).