2008-11-29 27 views
8

Estoy trabajando duro para encontrar una solución elegante a un problema de carga de DLL. Tengo una aplicación que enlaza estáticamente a otros archivos lib que cargan archivos DLL. No estoy cargando las DLL directamente. Me gustaría tener algunos archivos DLL en otra carpeta que no sea la carpeta en la que se encuentra el ejecutable. Algo como% working_folder% \ dlls - Prefiero no tener docenas (sí ... docenas) de archivos DLL en mi% working_folder% .agregar una ruta de búsqueda DLL personalizada @ aplicación de inicio

Estoy tratando de desarrollar algo que sea parte de la aplicación principal que ajustará la ruta de búsqueda @ inicio. El problema al que me estoy enfrentando es que esta nueva ruta personalizada de DLL no se encuentra en la ruta de búsqueda del sistema. Cuando inicio la aplicación, falla (STATUS_DLL_NOT_FOUND) porque los archivos DLL necesarios no se encuentran en los lugares adecuados. Lo que me gustaría hacer es marcar @ startup si esta nueva carpeta DLL personalizada se encuentra en la ruta de búsqueda de la variable de entorno de proceso y, si no, agréguela. El problema es que la aplicación intenta cargar todas estas DLL antes de que la aplicación ejecute una línea de código.

¿Cómo puedo solucionar esto? Consideré escribir una aplicación de ayuda que comience primero, ajuste las variables de entorno de forma adecuada y lance la aplicación principal a través de CreateProcess. Esto funcionará, estoy seguro, pero dificulta las cosas a los desarrolladores. Cuando depuran la aplicación principal, no van a lanzar primero una aplicación de ayuda, ni siquiera podrían hacer eso.

He intentado la función de ruta de la aplicación de registro sin éxito. Mismo problema de huevo y pollo que antes.

¿Qué puedo hacer aquí?

Respuesta

2

[Editar - después de volver a leer la pregunta veo que el problema que tiene es que los archivos DLL se cargan antes de conseguir main inicia]

que supongo que esas bibliotecas están escritas en C++ y son cargando las DLL desde el constructor de algunos objetos en alcance global. Esto es problemático Permitirme citar Yossi Kreinin:

Lo primero que hago en main(). Si usa C++, debe hacerlo primero antes que main(), porque las personas pueden usar FP en constructores de variables globales. Esto puede lograrse averiguando el orden de inicialización de la unidad de traducción específica del compilador, compilando su propia biblioteca de inicio C/C++, anulando el punto de entrada de una biblioteca de inicio compilada usando cosas como LD_PRELOAD, sobrescribiéndola en un programa enlazado estáticamente allí mismo en la imagen binaria, teniendo una convención de codificación forzando a llamar a FloatingPointSingleton :: instance() antes de usar FP, o disparar a las personas que les gusta hacer cosas antes de main(). Es una compensación.

[Respuesta original abajo]

Ver this page para el algoritmo de búsqueda utilizado para cargar archivos DLL. Puede usar SetDllDirectory() para agregar un directorio a la ruta de búsqueda de DLL.

También debería poder agregar un directorio a la variable de entorno PATH usando GetEnvironmentVariable() y SetEnvironmentVariable().

Otra opción es cambiar el directorio de trabajo actual a la carpeta que contiene los archivos DLL con SetCurrentDirectory(). Solo asegúrese de volver a cambiar el directorio de trabajo después de cargar los archivos DLL si alguna vez carga archivos con nombres de archivo relativos.

+0

qué Windows tiene algo así como @load_path en OS X? A saber, a la ruta de búsqueda definida relativa a la DLL actual o algo así? Gracias. – Royi

2

Mi recomendación es utilizar la vinculación de la carga de retraso para los archivos DLL y llamar a SetDllDirectory() lo suficientemente temprano para que pueda encontrarlos cuando se invocan los métodos/funciones.

+2

Nota: hay muchas cosas que no puede hacer en DllMain, como cargar valores de registro. Pero llamar a SetDllDirectory ("./ dll_dir") * podría * funcionar. No probado. –

3

Encontré que la respuesta de Matthew funcionó para mí.

en Visual Studio 2012 Goto las propiedades del proyecto y en configuración Properties-> Linker-> input-> Delay Cargado Dlls añadir cada archivo DLL que desea no cargar hasta que se necesite.

A pesar de que ya no tiene que correr antes de principal, este es mi código para establecer la nueva ruta de búsqueda

class RunBeforeMain 
{ 
public: 
    RunBeforeMain() 
    { 
     const TCHAR* dllPathEnvName= name of env variable to directory containing dlls 
     const TCHAR* pathEnvName= TEXT("Path"); 


     TCHAR newSearchPath[4096]; 
     ::GetEnvironmentVariable(dllPathEnvName, newSearchPath, MAX_PATH); 

      //append bin 
     _tcscat_s(newSearchPath, MAX_PATH, TEXT("bin;")); 
     size_t length = _tcslen(newSearchPath); 

      //append existing Path 
     ::GetEnvironmentVariable(pathEnvName, newSearchPath + length, 4096-length); 
     ::SetEnvironmentVariable(pathEnvName, newSearchPath); 

    } 
}; 
static RunBeforeMain runBeforeMain; //constructor code will run before main. 
Cuestiones relacionadas