Una forma de obtener la versión del sistema operativo usando .NET Compact Framework

A veces es necesario saber la versión del sistema operativo sobre la que está ejecutándose una aplicación .NET para tomar alguna deción sencilla. El ejemplo más claro que me he encontrado recientemente es el de usar la función Bitmap.Save en .NET Compact Framework para guardar un Bitmap a disco. Si se lee la documentación de esta función, se indica que se le puede pasar un parámetro de tipo ImageFormat (un enum) diciéndole el tipo de imagen a guardar. Entre los diferentes valores del enum se dispone de PNG por ejemplo. Pero si se intenta guardar un bitmap usando el formato PNG en un dispositivo Windows Mobile 2003 (cuya base de sistema operativo es Windows CE 4.2) obtendremos una excepción en tiempo de ejecución (NotSupportedException) ya que en Windows CE 4.2 GDI no dispone de la posibilidad de tratar PNGs. En cambio, si se ejecuta ese código en un dispositivo Windows Mobile 2005, basado en Windows CE 5.0, funcionará sin problemas.

Para evitar estos problemas basta con que detectemos la versión del sistema operativo para escoger un formato de imagen u otro dependiendo del tipo de dispositivo que sea.

Una forma de obtener rápidamente la versión del sistema operativo es mediante la función GetVersionEx del API de Windows. Su declaración sería similar a lo siguiente:

[DllImport("coredll.dll")]
public static extern int GetVersionEx(byte[] lpVersionInfo);

Si se busca la documentación de esta función, como parámetro se pide una estructura de tipo OSVERSIONINFO. En este caso (como en muchos otros en los que el API requiere estructuras) resulta casi más fácil pasarle a la función como parámetro un array de bytes que luego la función rellenará. Lo que necesitamos saber, eso si, es el tamaño del array a pasar, que se puede ver en la documentación (sumando los tamaños de los campos de la estructura). Luego, cuando la función rellene el array, se podrá leer fácilmente su contenido usando la clase BitConverter, lo que facilita mucho las declaraciones de p/invoke, ya que no hay que traducir las estructuras a .NET. Esta misma técnica está usada en el ejemplo de Ping para Compact Framework que podéis encontrar aquí.

Teniendo en cuenta esto, el código para obtener la versión será entonces algo parecido a:

byte[] lpVersionInfo = new byte[138];

int resp = GetVersionEx(lpVersionInfo);
if (resp == 1)
{
Int32 dwMajorVersion = BitConverter.ToInt32(lpVersionInfo, 4);
Int32 dwMinorVersion = BitConverter.ToInt32(lpVersionInfo, 8);
Int32 dwBuildNumber = BitConverter.ToInt32(lpVersionInfo, 12);
Int32 dwPlatformId = BitConverter.ToInt32(lpVersionInfo, 16);

}

Para un equipo con Windows Mobile 2003 el valor de dwMajorVersion será 4 y el de dwMinorVersion será mayor o igual a 2 (Windows CE 4.2). En el caso de un equipo Windows Mobile 2005 la versión será mayor o igual a 5.0.

Siguiendo el ejemplo anterior, la función Bitmap.Save pasándo como parámetro un formato de tipo PNG, funcionará sólo para equipos con dwMajorVersion >= 5.

¿Qué ha hecho Microsoft por nosotros?

Hace unos días vi en dev.licio.us (una comunidad similar a Geeks.ms) una viñeta que me resultó graciosa que supongo que no necesita explicación si habéis visto la película 'La vida de Brian':

(Traducción por si lo necesitáis:

Bien, bien, pero además de los Genéricos, los Métodos Anónimos, los iteradores, las Clases Parciales, LINQ, WPF y WCF, ¿qué ha hecho Microsoft por nosotros?

El frente de liberación de los Bloggers

)

😉

Primeros pasos con SandCastle y .NET Compact Framework

Después de la muerte prematura de NDOC 2.0 Microsoft ha liberado una utilidad que 'lo sustituye', llamada Sandcastle.

Para aquellos que no lo sepan, estas utilidades permiten generar documentación de código a partir de los assemblies y sus correspondientes documentos XML que genera por ejemplo Visual Studio, a partir de los comentarios del código. Usa además Reflection para obtener documentación adicional de las posibles dependencias que pueda usar nuestra aplicación.

Tenía previsto describir a la vuelta de vacaciones como funciona Sandcastle ya que es una herramienta un poco dura de usar, únicamente mediante línea de comandos, pero he encontrado un Wiki sobre el tema que no conocía y que hace referencia a algunas utilidades que ya se han escrito por ahí que proporcionan un interface de usuario para Sandcastle, con lo que se hace un poco irrelevante escribir ya sobre cómo usar los comandos para generar la documentación.

Una de las que más me ha gustado es 'Sandcastle Help File Builder' que tiene un interface de usuario casi idéntico al que tiene NDOC con lo que usarla se hace muy sencillo para los que ya hemos usado esa herramienta (si no se ha usado, es muy fácil de aprender).

Para usarla, lo primero que se necesita tener instalado es Sandcastle, al menos con la CTP de Agosto de 2006. Una vez hecho esto, simplemente hay que seleccionar un assembly que hayamos compilado con la opción de generación de documentación XML en Visual Studio y pedirle a la utilidad que compile el archivo de ayuda. La salida de SandCastle se ve en la parte inferior de la ventana mostrando si se ha producido algún error. Si todo ha funcionado como debiera, la herramienta generará un archivo de ayuda con la documentación del código.

Una opción interesante que incluye esta utilidad es la de poder abrir directamente un proyecto o solución de Visual Studio para que la herramienta lo inspeccione y cargue los assemblies de salida, agilizando aún más el proceso.

Una pequeña pega ocurre si pasamos a la utilidad un assembly o proyecto de .NET Compact Framework. Si lo hacemos sin más, veremos un error similar al siguiente (para un proyecto con UI):

Error: Unresolved assembly reference: System.Windows.Forms (System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=969db8053d3322ac) required by …

Para poder generar documentación de .NET Compact Framework adecuadamente, hay que indicarle a la utilidad que busque las dependencias de los assemblies de .NET Compact Framework en el sitio correcto ya que si no lo hacemos, intentará buscarlas en el GAC del PC en el que se ejecute, donde no las encontrará. Para ello simplemente hay que incluir en la colección de dependencias de la utilidad (en la sección Build) el directorio en el que se encuentran los assemblies correspondientes; que en una instalación en los directorios por defecto de Visual Studio y sustituyendo X.X por la versión correspondiente de .NET Compact Framework será similar a

C:Program FilesMicrosoft Visual Studio 8SmartDevicesSDKCompactFrameworkX.XvX.XWindowsCE

Una vez incluido el directorio en las dependencias, se puede compilar el archivo de ayuda sin problemas.