Wednesday, 10 November 2010

Error en ResGen.exe (archivos .ResX, especialmente en controles ImageList) al compilar con VisualStudio 2010

La ultima versión de VisualStudio incorpora algunas diferencias en el modo en que se invoca el proceso ResGen.exe que pueden convertir la migración a 2010 en una pesadilla.

Este error es un problema conocido, probablemente a solucionar en el próximo HotFix o Service Pack, y está bien documentado aqui. Aún así, traduciré y trataré de resumir lo que en ese post se comenta.

Síntomas

Al compilar, aparece un error de tipo: <<ResGen.exe error: An attempt was made to load a program with an incorrect format>>

Ejemplo concreto de un error de este tipo: <<ResourceForm.resx(1436,5): error RG0000: Could not load file or assembly 'file:///C:/Users/sjoiner/Desktop/TestForm/ResTest/bin/x86/Debug/Foo.dll' or one of its dependencies. An attempt was made to load a program with an incorrect format. Line 1436, position 5.>>

Ejemplo concreto de un error de este tipo en Castellano: <<ResourceForm.resx(1436,5): error RG0000: No se pudo cargar el ensamblado 'file:///C:/Users/sjoiner/Desktop/TestForm/ResTest/bin/x86/Debug/Foo.dll' o una de sus dependencias. Se intentó cargar un programa con un formato incorrecto. Line 1436, position 5.>>

Nota: La ruta y el nombre del ensamblado (Foo.dll) son solo un ejemplo. A cada uno os aparecerá ahí el nombre del más abajo llamado Ensamblado B.

Al hacer doble-click en el error, VisualStudio nos lleva automáticamente al archivo ResX del formulario.

Escenario donde se produce el error

  • Estamos en un sistema operativo de 64-bit
  • Y - Cualquier proyecto que contiene archivos de recursos .ResX (como Windows Forms). Le llamaremos Proyecto A
  • Y - El Proyecto A referencia un ensamblado (lo llamaremos Ensamblado B)
  • Y - Alguno de los archivos de recursos (.ResX) del Proyecto A utiliza algún tipo definido en el Ensamblado B
  • Y – Se da una de las siguientes combinaciones marcadas con una X en la siguiente tabla.

image

Es decir, el error aparecerá (resumen de los casos más frecuentes):

  • Siempre que el Proyecto A se esté compilando para .Net Framework 3.5 o inferior, y el Ensamblado B esté compilado específicamente para 32-bits.
  • O - Siempre que el Proyecto A se esté compilando para .Net Framework 4.0, y el Proyecto A y el Ensamblado B estén compilados para plataformas específicas, que además sean distintas.

Soluciones, o más bien apaños

Mientras Microsoft no distribuya un Service Pack que solucione esté problema, lo único que se pueden hacer son apaños más bien cutres.

Apaño 1 – Evitar los escenarios críticos descritos en la tabla, cambiando la plataforma de compilación al Ensamblado B, a una plataforma que no entre en conflicto según la tabla de arriba. O mejor aún, poniéndole como plataforma “Any CPU”. Obviamente, esto no siempre es posible (si el ensamblado es de una tercera empresa, por ejemplo).

Apaño 2.- Evitar los escenarios críticos descritos en la tabla, cambiando la plataforma de compilación del Proyecto A. Por ejemplo, pasando dicho proyecto a .Net Framework 4.0. Obviamente, esto tampoco es siempre posible.

Apaño 3 - Ordenar a ResGen.Exe que siempre se ejecute en 32 bits, haciendo lo siguiente:

  1. 1. Cd “%ProgramFiles(x86)%\Microsoft SDKs\Windows\v7.0A\Bin”
  2. 2. Corflags /32Bit+ /Force ResGen.exe

Lamentablemente, esto provoca un segundo error de tipo: “The specified task executable "ResGen.exe" could not be run. The handle is invalid”. Para solucionarlo tenemos 3 opciones:

  1. 1. Añadir la propiedad <ResGenToolArchitecture>Managed32Bit</ResGenToolArchitecture> a un PropertyGroup en los archivos de todos los proyectos que generen archivos ResX.
  2. 2. O – Si se está invocando MSBuild.exe directamente, pasarle el parámetro /p:ResGenToolArchitecture=Managed32Bit
  3. 3. O – Establecer una variable de entorno en la ventana Command en la que se está ejecutando MSBuild.exe o desde la cual se está abriendo el entorno de VStudio.  ‘set RESGENTOOLARCHITECTURE=Managed32Bit’

Apaño 4 – Forzar al CLR a cargar todas las aplicaciones MSIL en 32-bits, haciendo lo siguiente:

  1. 1. Cd “%windir%\Microsoft.NET\Framework64\v2.0.50727”
  2. 2. Ldr64.exe setwow

Esta solución no me gusta nada, ya que afectará a todo tu sistema y a todas las aplicaciones .Net que ejecutes.

Conclusiones

Este problema resulta una molestia bastante importante, y por el momento no hay una solución satisfactoria. En el IDE de VisualStudio, debería poder especificarse el Bitness en el que deseamos que se ejecute ResGen.Exe para cada proyecto. No parece una solución tan compleja de implementar, así que esperemos se incluya pronto en un HotFix.

Si deseas saber más sobre este problema, así como leer conversaciones con las experiencias de otros usuarios, te recomiendo que leas el Post original (en inglés), disponible aqui.

Saludos!

No comments: