2008-11-29 9 views
8

Mi sto tormentando il cervello cercando di trovare una soluzione elegante a un problema di caricamento della DLL. Ho un'applicazione che si collega staticamente ad altri file lib che caricano DLL. Non sto caricando direttamente le DLL. Mi piacerebbe avere alcune DLL in un'altra cartella diversa dalla cartella in cui si trova l'eseguibile. Qualcosa come% working_folder% \ dlls - Preferirei non avere dozzine (sì ... dozzine) di DLL nel mio% working_folder% .aggiungi percorso di ricerca DLL personalizzato all'avvio dell'applicazione

Sto provando a sviluppare qualcosa che fa parte dell'app principale che regolerà il percorso di ricerca @ startup. Il problema che sto incontrando è che questo nuovo percorso DLL personalizzato non si trova nel percorso di ricerca del sistema. Quando avvio l'app si blocca (STATUS_DLL_NOT_FOUND) perché le DLL necessarie non si trovano nelle posizioni appropriate. Quello che mi piacerebbe fare è controllare @ startup se questa nuova cartella DLL personalizzata si trova nel percorso di ricerca della variabile di ambiente di processo e se non la aggiunge. Il problema è che l'applicazione tenta di caricare tutte queste DLL prima che l'app esegua una riga di codice.

Come posso risolvere questo problema? Ho preso in considerazione la scrittura di un'app di guida che inizia per prima, regola le variabili di ambiente in modo appropriato e avvia l'app principale tramite CreateProcess. Questo funzionerà ne sono sicuro, ma rende le cose difficili agli sviluppatori. Quando eseguono il debug dell'applicazione principale, non avviano prima un'app helper, non che potrebbero persino farlo.

Ho provato la funzionalità del percorso dell'app del registro senza esito. Lo stesso problema con il pollo e le uova di prima.

Cosa posso fare qui?

risposta

2

[Edit - dopo aver riletto la domanda vedo che il problema che stai avendo è che le DLL sono sempre caricati prima main inizia]

Sto indovinando che queste librerie sono scritte in C++ e sono caricamento delle DLL dal costruttore di alcuni oggetti nell'ambito globale. Questo è problematico. Permettetemi di quotare Yossi Kreinin:

Fatelo per prima cosa in main(). Se usi C++, dovresti farlo prima di main(), perché le persone possono usare FP nei costruttori di variabili globali. Ciò può essere ottenuto calcolando l'ordine di inizializzazione dell'unità di traduzione specifica del compilatore, compilando la propria libreria di avvio C/C++, sovrascrivendo il punto di ingresso di una libreria di avvio compilata utilizzando elementi come LD_PRELOAD, sovrascrivendoli in un programma collegato staticamente proprio lì nell'immagine binaria, avendo una convenzione di codifica che costringe a chiamare FloatingPointSingleton :: instance() prima di usare FP, o sparare alle persone a cui piace fare cose prima di main(). È un trade-off.

[risposta originale sotto]

Vedere this page per l'algoritmo di ricerca utilizzato per le DLL di carico. È possibile utilizzare SetDllDirectory() per aggiungere una directory al percorso di ricerca DLL.

Dovresti anche essere in grado di aggiungere una directory alla variabile d'ambiente PATH utilizzando GetEnvironmentVariable() e SetEnvironmentVariable().

Un'altra opzione consiste nel modificare la directory di lavoro corrente nella cartella contenente le DLL con SetCurrentDirectory(). Assicurati di cambiare la directory di lavoro dopo aver caricato le DLL se carichi qualsiasi file usando nomi di file relativi.

+0

fa di Windows ha qualcosa come @load_path in OS X? Vale a dire definito percorso di ricerca relativo alla DLL corrente o qualcosa del genere? Grazie. – Royi

2

Il mio consiglio è di utilizzare il collegamento di caricamento in ritardo per le DLL e chiamare SetDllDirectory() abbastanza presto in modo che possa trovarli quando vengono invocati i metodi/le funzioni.

+2

Nota: ci sono molte cose che non puoi fare in DllMain, come ad esempio caricare i valori di registro. Ma chiamare SetDllDirectory ("./ dll_dir") * potrebbe * funzionare. Non testato. –

3

Ho trovato che la risposta di Matthew ha funzionato per me.

in Visual Studio 2012 goto le proprietà del progetto e in Configurazione Proprietà-> Linker-> INPUT-> Ritardo Loaded Dlls aggiungere ogni file dll che si desidera non caricare fino a quando necessario.

Anche se non ha più bisogno di correre prima principale, questo è il mio codice per impostare il nuovo percorso di ricerca

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.