microsoft - ¿Puedo usar el compilador C++ de Visual Studio 2010 con C++ Runtime Library de Visual Studio 2008?
microsoft visual c++ 2017 (8)
Tengo una aplicación que necesita operar en Windows 2000. También me gustaría usar Visual Studio 2010 (principalmente debido al cambio en la definición de la palabra clave auto
). Sin embargo, estoy un poco comprometido porque necesito que la aplicación pueda operar en sistemas operativos anteriores, a saber:
- Windows 2000
- Windows XP RTM
- Windows XP SP1
La biblioteca de tiempo de ejecución de Visual Studio 2010 depende de la API EncodePointer / DecodePointer
que se introdujo en Windows XP SP2.
Si es posible usar la biblioteca de tiempo de ejecución alternativa, ¿romperá este código que se basa en las características de C ++ 0x agregadas en VS2010, como std::regex
?
Como Visual Studio viene con soporte para MASM (ver propiedades del proyecto -> Personalizaciones de compilación ...) la siguiente traducción del código de snemarch a MASM podría ser útil:
.model flat
.data
__imp__EncodePointer@4 dd dummy
__imp__DecodePointer@4 dd dummy
EXTERNDEF __imp__EncodePointer@4 : DWORD
EXTERNDEF __imp__DecodePointer@4 : DWORD
.code
dummy proc
mov eax, [esp+4]
ret 4
dummy endp
end
Y recuerde configurar Linker-> System-> Minimum Required Version a 5.0 (por defecto es 5.1) para ejecutar en Windows 2000.
Cree un .LIB que implemente la funcionalidad faltante y vincule antes de KERNEL32.LIB.
Tendrá que utilizar la opción del vinculador /NODEFAULTLIB:kernel32.lib para que pueda poner su w2kcompat.lib por delante de kernel32.lib.
Esto sería mucho más fácil si se le permite usar una DLL. Básicamente, escriba un EXE que no requiera ninguna función de tiempo de ejecución de C, utilizando la función del enlazador / ENTRYPOINT. Una vez que haya comprobado que se cumplen sus requisitos previos básicos y haya informado de cualquier problema al usuario a través de las API provistas por Windows disponibles en todos los sistemas operativos de destino (es decir, MessageBox), llame a LoadLibrary para iniciar la DLL que contiene la mayor parte de su lógica . Esa DLL puede usar el tiempo de ejecución VS2010 como de costumbre. Incluso puede evitar implementar dos archivos separados al descomprimir la DLL de un recurso contenido en su .EXE principal al inicio. (Puede hacer esto completamente dentro de la memoria sin escribir .DLL en el disco, pero no si desea aprovechar el cargador de Windows PE para arreglar todas sus importaciones).
La solución habitual para este problema es crear su propia versión personalizada de CRT. Aquí hay instrucciones para esto. Solo tendrá que editar el código para ignorar EncodePointer
y DecodePointer
. (Ya debería haber un #define
para eso).
Hay otras dos cosas menores que deberá hacer:
- Vaya a la configuración Enlazador-> Directorios de biblioteca adicionales y establezca
C:/Microsoft Visual Studio 9.0/VC/lib
como la primera ruta de búsqueda. (Supongo que utilizó el directorio de instalación predeterminado, de lo contrario, cambie según corresponda). - Cambie la versión del subsistema, en el encabezado PE, a 5.00 (use el CFF Explorer Suite gratis si no tiene otra herramienta a mano para ello).
Eso debería permitir que su programa se ejecute en Windows 2000, así como en versiones posteriores.
La solución más sencilla es simplemente configurar Platform Toolset en la configuración del proyecto en VS2010 a v900, que utilizará las bibliotecas y el compilador de Visual Studio 2008. Esto también significa que usted pierde las características de C ++ 0x como auto
, pero para ser honesto, trabajar con algunas typedef
es probablemente más fácil que construir su propia versión del CRT u otras soluciones más complicadas. Alternativamente, solo use VS2008! No sé si hay otras características de C ++ 0x que son críticas para su aplicación, sin mencionar, aparte de std::regex
, que creo que todavía está en el conjunto de herramientas v900 en el espacio de nombres del informe técnico 1 ( std::tr1::regex
).
Solo por la impresión que tengo, podría predecir que la inconveniencia de hacer que las bibliotecas VS2010 se ejecuten en XP SP1 es mayor que la comodidad de las características de C ++ 0x, por lo que, en general, no valdría la pena.
No puede usar 2008 CRT, pero puede evitar que las nuevas funciones DecodePointer / EncodePointer se vinculen desde el kernel. Es bastante fácil reemplazar las nuevas funciones con stubs.
Uno podría intentar seguir: coloque un código como este en su fuente main.cpp:
extern "C" {
void *__stdcall _imp__DecodePointer(void *x) {return x;}
void *__stdcall _imp__EncodePointer(void *x) {return x;}
};
Lo anterior no funciona. Si bien la idea básica es sólida, la ejecución debe ser un poco diferente. Como se describe por snemarch en el comentario y en otra respuesta , __imp__
no puede ser la llamada a la función, solo el puntero a ella. Como parece que no es posible generar el puntero directamente por el compilador, debe ensamblar el siguiente código con MASM y vincularlo con el archivo de objeto producido.
.model flat
.data
__imp__EncodePointer@4 dd dummy
__imp__DecodePointer@4 dd dummy
EXTERNDEF __imp__EncodePointer@4 : DWORD
EXTERNDEF __imp__DecodePointer@4 : DWORD
.code
dummy proc
mov eax, [esp+4]
ret 4
dummy endp
end
Los símbolos de un proyecto tienen preferencia contra cualquier símbolo de las bibliotecas. Las bibliotecas DLL se vinculan usando partes .lib, que contienen solo "vectores" __imp__
"saltando a las funciones reales. Al reemplazar __imp__
"vectores" no toca el enlace DLL, reemplaza la parte .lib. He verificado que ya no existe ninguna dependencia del exe en DecodePointer / EncodePointer.
Fondo
La biblioteca enlazada estáticamente solo trae funcionalidad utilizada a la aplicación. Es posible encontrar qué función CRT particular traer en esas nuevas API utilizando salida de progreso detallado linker:
Found __imp__EncodePointer@4
Referenced in LIBCMT.lib(crtmboxw.obj)
Referenced in LIBCMT.lib(invarg.obj)
Referenced in LIBCMT.lib(handler.obj)
Referenced in LIBCMT.lib(onexit.obj)
Referenced in LIBCMT.lib(cmiscdat.obj)
Referenced in LIBCMT.lib(tidtable.obj)
Referenced in LIBCMT.lib(hooks.obj)
Referenced in LIBCMT.lib(winsig.obj)
Referenced in LIBCMT.lib(rand_s.obj)
Found __imp__DecodePointer@4
// ... same list, only order differs ...
Esto muestra que las nuevas API se utilizan en algunos de los CRT para proporcionar más seguridad para algunas funciones que se considera que proporcionan vectores de ataque frecuentes.
Con un poco de esfuerzo, sería posible usar LoadLibrary / GetProcAddress para proporcionar la verdadera funcionalidad donde se encuentra el sistema operativo, pero no creo que realmente traiga algo. Las funciones de tiempo de ejecución que utilizan DecodePointer / EncodePointer realmente no necesitan proporcionar ninguna codificación, todo lo que necesitan es la codificación simétrica. Realmente no necesita la seguridad mejorada (el tiempo de ejecución de VS 2008 tampoco se lo daría).
Espero que no haya otros obstáculos esperándote: no tengo acceso al sistema Win2k o XP pre SP2, por lo tanto no puedo probar. Si hay indicadores de encabezado de exe que impiden incluso intentar ejecutar el exe en dichos sistemas, deberían ser fáciles de cambiar.
Opción 1: cree una versión modificada del tiempo de ejecución de 2010 que redirija las llamadas problemáticas de la API a una DLL que proporcione. No sé cuán fácil o difícil sería (con la esperanza de que sea solo un pequeño cambio en la tabla de símbolos, depende del formato del archivo) y es muy probable que se tope con la cláusula de ingeniería inversa de la licencia, por supuesto. .
Opción 2: compare los símbolos exportados en dos versiones diferentes de las libs de tiempo de ejecución. Si los símbolos son los mismos, tiene buenas probabilidades de compatibilidad, aunque no hay garantías. Incluso es posible que los formatos de archivo lib sean diferentes.
Opción 3: compruebe si puede obtener acceso a fuentes de tiempo de ejecución a través de MSDN o similar, específicamente para crear una versión parchada.
Opción 4: compruebe si puede usar el compilador de 2010, pero un enlazador anterior, quizás configurado en sus soluciones como un paso de compilación personalizado. De nuevo, esto depende de si los archivos obj y lib tienen el mismo formato de archivo, pero es posible que pueda escribir una pequeña utilidad para parchar diferencias simples como números de versión en un encabezado. El enlazador anterior no debería tener problemas para vincularse en el tiempo de ejecución anterior, suponiendo que los objs del nuevo compilador sean compatibles con él.
Opción 5: compilar archivos DLL en 2010 que no necesitan su propio tiempo de ejecución, pero que se cargan y alojan en una aplicación creada con el compilador anterior. Lograr el requisito "sin tiempo de ejecución" para sus archivos DLL puede significar que muchas de sus bibliotecas deben estar integradas en la aplicación de alojamiento, por supuesto, y es posible que deba proporcionar sus propias interfaces (a través de la aplicación host) a las funciones de la biblioteca que necesita para trabajar con - especialmente cosas de asignación de memoria.
Merece la pena verificar las opciones, pero estoy seguro de que ya las pensó todas, lo siento, no tengo idea de si alguna de ellas funcionará, o si funcionarán casi por completo, pero ocasionarán problemas intermitentes.
La solución de Suma parecía bastante prometedora, pero no funciona: los __imp__*@4
necesitan ser indicadores de funciones, en lugar de las funciones mismas. Lamentablemente, no sé cómo hacer que Visual C ++ escupe un puntero con ese tipo de generación de nombres ... (bueno, __declspec(naked)
combinado con __stdcall
hace el truco, pero entonces no sé cómo emitir un puntero).
Si está bien utilizar un ensamblador en tiempo de compilación, la solución es bastante trivial: ensamble el siguiente código con FASM y vincule con el archivo de objeto producido, y presto - sin referencias EncodePointer / DecodePointer en el archivo ejecutable:
use32
format ms coff
section ".data" data
public __imp__DecodePointer@4
__imp__DecodePointer@4 dd dummy
public __imp__EncodePointer@4
__imp__EncodePointer@4 dd dummy
section ".text" code
dummy:
mov eax, [esp+4]
retn 4