La aplicación no se ejecuta con VS 2008 SP1 DLL, la versión anterior funciona con versiones RTM

Desde nuestro cambio de Visual Studio 6 a Visual Studio 2008, hemos estado usando MFC90.dll y msvc [pr] 90.dlls junto con los archivos de manifiesto en una configuración privada de lado a lado para no preocuparnos por las versiones o instalándolos en el sistema.

Pre-SP1, esto funcionaba bien (y aún funciona bien en nuestras máquinas de desarrollo). Ahora que hemos hecho algunas pruebas post-SP1, me he estado tirando de los pelos desde ayer por la mañana.

En primer lugar, nuestra secuencia de comandos del instalador de NSIS extrae los dlls y los archivos de manifiesto de la carpeta de redistribución. Estos ya no eran correctos, ya que la aplicación todavía se vincula a la versión RTM.

Así que agregué la definición de _BIND_TO_CURRENT_VCLIBS_VERSION=1 a todos nuestros proyectos para que usen las DLL de SP1 en la carpeta de redistas (o las siguientes a medida que aparezcan los nuevos paquetes de servicios). Me llevó horas encontrar esto.

He comprobado dos veces los archivos manifiestos generados en la carpeta de archivos intermedios de la comstackción, y enumeran correctamente las versiones 9.0.30729.1 SP1. He comprobado dos y tres veces depende de una máquina limpia: todos los enlaces a las dlls locales sin errores.

La ejecución de la aplicación sigue recibiendo el siguiente error:

La aplicación no se inicializó correctamente (0xc0150002). Haga clic en Aceptar para terminar la aplicación.

Ninguna de las búsquedas que he realizado en google o microsoft ha encontrado algo que se relacione con mis problemas específicos (pero hay éxitos en 2005 con este mensaje de error).

¿Alguien tuvo algún problema similar con SP1?

Opciones:

  • Encuentre el problema y corríjalo para que funcione como debería (preferido)
  • Instala la redista
  • desenterrar los dll viejos RTM y los archivos de manifiesto y eliminar el #define para usar los actuales. (Los tengo en una comstackción de instalador anterior, ¡ya que Microsoft los saca de la carpeta redist!)

Editar: He intentado reconstruir con la definición desactivada (enlace a dlls RTM), y eso funciona siempre que los dlls de RTM estén instalados en la carpeta. Si los dlls SP1 se agregan, obtiene el siguiente error:

c: \ Archivos de progtwig \ … \ … \ X.exe

Esta aplicación no ha podido iniciarse porque la configuración de la aplicación es incorrecta. Reinstalar la aplicación podría resolver el problema.

¿Nadie más ha tenido que lidiar con este problema?

Editar: Solo por sonrisas, descargué y ejecuté el vcredist_x86.exe para VS2008SP1 en mi máquina de prueba. Funciona Con las DLL SP1. Y mi aplicación vinculada RTM. Pero NO en una distribución privada de lado a lado que funcionó antes de SP1.

He luchado este problema yo mismo la semana pasada y ahora me considero una especie de experto;)

Estoy 99% seguro de que no todas las bibliotecas dlls y estáticas fueron recomstackdas con la versión SP1. Tienes que poner

 #define _BIND_TO_CURRENT_MFC_VERSION 1 #define _BIND_TO_CURRENT_CRT_VERSION 1 

en cada proyecto que estás usando Para cada proyecto de tamaño real, es muy fácil olvidar alguna lib pequeña que no se volvió a comstackr.

Hay más indicadores que definen a qué versiones vincularse; está documentado en http://msdn.microsoft.com/en-us/library/cc664727%28v=vs.90%29.aspx . Como alternativa a las líneas anteriores, también puede poner

 #define _BIND_TO_CURRENT_VCLIBS_VERSION 1 

que se unirá a la última versión de todas las librerías de VC (CRT, MFC, ATL, OpenMP).

Luego, verifique qué dice el manifiesto incrustado. Descargue el Editor de recursos de XM: http://www.wilsonc.demon.co.uk/d10resourceeditor.htm . Abra cada dll y exe en su solución. Mire debajo de ‘Manifiesto temático de XP’. Compruebe que el atributo ‘versión’ en el lado derecho es ‘9.0.30729.1’. Si es ‘9.0.21022’, alguna biblioteca estática está tirando del manifiesto para la versión anterior.

Lo que encontré es que en muchos casos, ambas versiones se incluyeron en el manifiesto. Esto significa que algunas bibliotecas usan la versión sp1 y otras no.

Una forma excelente de depurar qué bibliotecas no tienen establecidas las directivas de preprocesador: modifique temporalmente los encabezados de la plataforma para que la comstackción se detenga cuando intente incrustar el manifiesto anterior. Abra C: \ Archivos de progtwig \ Microsoft Visual Studio 9.0 \ VC \ crt \ include \ crtassem.h. Busque la cadena ‘21022’. En esa definición, ponga algo inválido (cambie ‘definir’ a ‘blehbleh’ o más). De esta forma, cuando está comstackndo un proyecto donde el indicador del preprocesador _BIND_TO_CURRENT_CRT_VERSION no está configurado, su comstackción se detendrá y sabrá que debe agregarlos o asegurarse de que se aplique en todas partes.

También asegúrese de usar Dependency Walker para que sepa qué dlls están siendo instalados. Es más fácil instalar una copia nueva de Windows XP sin actualizaciones (solo SP2) en una máquina virtual. De esta forma, puede estar seguro de que no hay nada en la carpeta SxS que se esté utilizando en lugar de los dlls lado a lado que suministró.

Para entender el problema, creo que es importante darse cuenta de que hay cuatro números de versión involucrados :

  • (A) La versión de los archivos de encabezado de VC a los que se comstack el .exe.
  • (B) La versión del archivo de manifiesto que está incrustado en la sección de recursos de ese .exe. De forma predeterminada, Visual Studio genera automáticamente este archivo de manifiesto.
  • (C) La versión de .DLL de VC (parte del conjunto de lado a lado) que copia en el mismo directorio que el .exe.
  • (D) La versión de los archivos de manifiesto de VC (parte del conjunto de lado a lado) que copia en el mismo directorio que el .exe.

Hay dos versiones de las DLL de VC 2008 en ejecución:

  • v1: 9.0.21022.8
  • v2: 9.0.30729.4148

Para mayor claridad, usaré la notación v1 / v2. La siguiente tabla muestra varias situaciones posibles:

 Situation | .exe (A) | embedded manifest (B) | VC DLLs (C) | VC manifests (D) ----------------------------------------------------------------------------- 1 | v2 | v1 | v1 | v1 2 | v2 | v1 | v2 | v2 3 | v2 | v1 | v2 | v1 4 | v2 | v2 | v2 | v2 

Los resultados de estas situaciones al ejecutar el .exe en una instalación limpia de Vista SP1 son:

  • Situación 1: se muestra una ventana emergente que dice: “El punto de entrada al procedimiento XYZXYZ no se pudo ubicar en la biblioteca de enlaces dynamics”.

  • Situación 2: nada parece suceder cuando se ejecuta el .exe, pero el siguiente evento se registra en el “Visor de sucesos / registro de aplicación” de Windows:

    La generación del contexto de activación falló para “C: \ Path \ file.exe” .Error en el archivo de manifiesto o de política “C: \ Path \ Microsoft.VC90.CRT.MANIFEST” en la línea 4. La identidad del componente encontrada en el manifiesto no coincide con la identidad del componente solicitado. La referencia es Microsoft.VC90.CRT, processorArchitecture = “x86”, publicKeyToken = “1fc8b3b9a1e18e3b”, type = “win32”, version = “9.0.21022.8”. La definición es Microsoft

  • Situación 3: todo parece funcionar bien. Esta es la solución de remicles2 .

  • Situación 4: así es como debería hacerse . Lamentablemente, como indica Roel, puede ser bastante difícil de implementar.

Ahora, mi situación (y creo que es la misma que la de crashmstr ) es nr 1. El problema es que Visual Studio por una razón u otra genera código de cliente (A) para v2, pero por una razón u otra, genera un manifiesto v1 archivo (B). No tengo idea de dónde se puede configurar la versión (A).

Tenga en cuenta que toda esta explicación todavía se encuentra en el contexto de las asambleas privadas .

Actualización : finalmente empiezo a entender lo que está pasando. Aparentemente, Visual Studio genera código de cliente (A) para v2 de forma predeterminada , al contrario de lo que he leído en algunos blogs de Microsoft. El indicador _BIND_TO_CURRENT_VCLIBS_VERSION solo selecciona la versión en el archivo de manifiesto generado (B), pero esta versión se ignorará al ejecutar la aplicación.

Conclusión

Un .exe comstackdo por Visual Studio 2008 vincula a las versiones más recientes de las DLL de VC90 de forma predeterminada. Puede usar el indicador _BIND_TO_CURRENT_VCLIBS_VERSION para controlar qué versión de las bibliotecas de VC90 se generará en el archivo de manifiesto. De hecho, esto evita la situación 2 en la que aparece el mensaje de error “el manifiesto no coincide con la identidad del componente solicitado”. También explica por qué la situación 3 funciona bien, ya que incluso sin el indicador _BIND_TO_CURRENT_VCLIBS_VERSION la aplicación está vinculada a las versiones más recientes de las DLL de VC.

La situación es aún más extraña con los ensamblados públicos lado a lado, donde se ejecutó vcredist, colocando las DLL de VC 9.0 en el directorio de Windows SxS. Incluso si el archivo de manifiesto de .exe indica que se deben usar las versiones anteriores de los archivos DLL (este es el caso cuando el indicador _BIND_TO_CURRENT_VCLIBS_VERSION no está configurado), Windows ignora este número de versión de forma predeterminada. En cambio, Windows usará una versión más nueva si está presente en el sistema, excepto cuando se usa un “archivo de configuración de la aplicación” .

¿Soy el único que piensa que esto es confuso?

Entonces en resumen :

  • Para ensamblados privados, use el indicador _BIND_TO_CURRENT_VCLIBS_VERSION en el proyecto .exe y todos los proyectos .lib dependientes.
  • Para las asambleas públicas, esto no es necesario, ya que Windows seleccionará automáticamente la versión correcta de los .DLL del directorio SxS.

Acabo de recordar otro truco que utilicé para descubrir qué bibliotecas estáticas se comportaban mal: ‘grep’ a través de las bibliotecas estáticas para la cadena ‘21022’. SIN EMBARGO, no use las herramientas grep ‘normales’ como wingrep porque no le mostrarán estas cadenas (creen que se trata de un archivo binario y buscan la cadena en bruto, no unicode). Use la utilidad ‘cadenas’ del kit de recursos (ahora en el sitio de Russinovich, creo). Ese se grep a través de binarios bien. Así que dejas que estas ‘cadenas’ recorran todo el árbol de fonts y verás los archivos binarios (dlls y bibliotecas estáticas) que contienen referencias al manifiesto incorrecto (o al manifiesto con la versión incorrecta en él).

Otra buena herramienta para ver los manifiestos exe y dll es Manifest View , que no se ejecutará adecuadamente en una instalación limpia de XP, ya que depende de 9.0.21022.

Para su tercera opción, probablemente pueda encontrar las DLL y los manifiestos para la versión 9.0.21022 en el directorio C: \ WINDOWS \ WinSxS en su máquina de desarrollo. Si puede, puede configurar su propio directorio de redistas e instalar esos archivos con su aplicación.

Alternativamente, puede usar los 9.0.30729.1 provistos con Visual Studio y falsificar el manifiesto que instala con su aplicación para informar que proporciona los archivos DLL 9.0.21022 y no 9.0.30729.1. Al enrutador de tiempo de ejecución no parece importarle. Vea este blog , que ha sido inmensamente útil para resolver estos problemas, para obtener más información.

Ambas soluciones arreglaron los problemas que tuve al implementar las DLL como ensamblajes privados con VS2008 Express.

La respuesta de Roel es el camino a seguir para su primera opción (“corregirlo bien”), pero si depende de una biblioteca que depende de 9.0.21022 (y su manifiesto, por lo tanto, enumera ambas versiones), entonces la tercera opción puede ser la única camino a seguir si no desea ejecutar vcredist_x86.exe.