C++: Manifiesta y carga dinĂ¡micamente DLL de diferentes directorios
manifest loadlibrary (3)
Larga historia de lo que intento lograr
Estoy trabajando en un programa que carga dinámicamente archivos DLL como complementos. Estoy compilando el programa usando Microsoft Visual C ++ 2008. Aun así, supongamos que cualquier versión de Visual C ++ con la que Qt funcione debería ser compatible. El diseño del directorio del programa es el siguiente:
| plugins/
| plugin1.dll
| plugin2.dll
| QtCore4.dll
| QtGui4.dll
| program.exe
program.exe
descubre todos los complementos de los archivos DLL, realiza LoadLibrary () en ellos y llama a una determinada función de firma para averiguar si realmente es un plugin o no. Esto funciona bastante bien en computadoras que tienen vcredist para MSVC90 instalado. Naturalmente, para hacer que el programa funcione en todas las computadoras, tengo que redistribuirlo con los archivos msvc * .dll y con el archivo de manifiesto apropiado. Qt DLL también requiere que se ejecute la redista.
Ahora, configuré cmake para que copie automáticamente las DLL de rediscado apropiadas y se manifieste en función de la versión de Visual Studio seleccionada. En aras de la simplicidad, sigamos asumiendo que estoy trabajando con MSVC90. Cuando la redista se copia en el directorio del programa, el diseño se ve así:
| plugins/
| plugin1.dll
| plugin2.dll
| QtCore4.dll
| QtGui4.dll
| msvcm90.dll
| msvcp90.dll
| msvcr90.dll
| Microsoft.VC90.CRT.manifest (I''m also aware that this file is bugged in VS2008)
| program.exe
En cuanto al error en el archivo de manifiesto: http://www.cmake.org/pipermail/cmake/2008-September/023822.html
El problema
El programa con este diseño ahora funciona en computadoras que no tienen el redist instalado, pero los complementos no se están cargando. Para poder cargar los complementos, debo hacer uno de los siguientes:
- Copie el archivo de manifiesto a
plugins/
directorio. Elimine todas las referencias a archivos msvc * .dll del archivo de manifiesto. Esto funciona, pero no es bueno porque tendría que admitir diferentes versiones de archivos de manifiesto editados según la versión del MSVC utilizado. Además, no tengo idea si esto no se romperá con Visual Studio que no sea 2008. - Copie toda la redistribución a
plugins/
directorio. Esto no requiere ninguna modificación en el archivo de manifiesto, pero ahora elprogram.exe
intenta estúpidamente cargar los archivos msvc * .dll pensando que son complementos. Naturalmente, esto falla con gracia por lo que no se hace gran daño. El otro inconveniente es que el tamaño del paquete de programa crece en más de 1 MB. Sin embargo, estos dos problemas son algo con lo que puedo vivir. - Compilar complementos con el modificador / MT. Las pruebas breves han demostrado que esto realmente funciona, pero no estoy seguro si no se romperá nada en el futuro si Qt y
program.exe
son / MD.
Las preguntas)
¿Cuál es la mejor solución? ¿Cuál es la solución correcta? Si hay más de una solución correcta, ¿cuál es la mejor práctica? ¿Soy la primera persona en intentar hacer esto alguna vez?
Actualización 1 (18 de noviembre de 2012)
Si bien la pregunta sigue sin respuesta, decidí ir por la ruta que causa menos dolor de cabeza. Hasta ahora he estado usando la solución número 1 y decidí seguir con ella. Si CMake detecta que el usuario está usando una versión diferente de MSVC que 2008, mostrará un mensaje de advertencia que indica que el empaque automático no es totalmente compatible.
Si su sistema operativo objetivo tiene _WIN32_WINNT> = 0x0502, entonces puede usar la función
SetDllDirectory()
antes de cargar los complementos
Ponga el camino a la carpeta del programa principal.
La llamada anula la orden de carga del sistema:
- El directorio desde el que se cargó la aplicación.
- El directorio especificado por la ruta en la llamada SetDllDirectory ().
Por lo tanto, puede llamar a la función después de que se inicie la aplicación. Es seguro en todos los casos. ¡Buena suerte!
Puede crear enlaces duros a las DLL de VC con la función CreateHardLink () en el proceso de instalación. Con el método (1) que ha descrito, puede haber algunos problemas con copias diferentes de dlls de VCRT. Hardlinks o SetDllDirectory () parece ser la mejor solución.
No mezcle en un solo proceso el enlace estático y dinámico con MSVCRT, ¡SIEMPRE le da problemas!
Puede proporcionar rutas de archivos completas a "LoadLibrary", para que pueda cargar sus complementos con sus rutas. He utilizado este diseño exacto para cargar múltiples versiones de la misma biblioteca desde los subdirectorios de la dll actual en Visual Studio 2005.
Primero necesita obtener la ruta actual del dll actual usando:
static LPSTR strDLLPath1 = new TCHAR[_MAX_PATH+1];
::GetModuleFileName((HINSTANCE)&__ImageBase, strDLLPath1, _MAX_PATH);
Aunque si su programa.exe ya está descubriendo estos archivos de complemento, supongo que ya tiene acceso a sus rutas completas.