2008-11-29 5 views
8

Ich bin mein Gehirn versucht, mit einer eleganten Lösung für ein DLL-Ladeproblem zu kommen. Ich habe eine Anwendung, die statisch mit anderen lib-Dateien verknüpft, die DLLs laden. Ich lade die DLLs nicht direkt. Ich hätte gerne einige DLLs in einem anderen Ordner als dem Ordner, in dem sich die ausführbare Datei befindet. So etwas wie% working_folder% \ dlls - ich hätte lieber nicht Dutzende (ja ... Dutzende) von DLLs in meinem% Arbeitsordner% .fügen Sie benutzerdefinierte DLL Suchpfad @ Anwendung Start

Ich versuche, etwas zu entwickeln, das Teil der Haupt-App ist, die den Suchpfad @ Start anpassen wird. Das Problem ist, dass dieser neue benutzerdefinierte DLL-Pfad nicht im Systemsuchpfad enthalten ist. Wenn ich die App starte, stürzt es ab (STATUS_DLL_NOT_FOUND), weil die notwendigen DLLs nicht an den richtigen Stellen sind. Ich möchte @ startup überprüfen, wenn sich dieser neue benutzerdefinierte DLL-Ordner im Suchpfad der Prozessumgebungsvariablen befindet, und wenn er nicht hinzugefügt wird. Das Problem ist, dass die Anwendung versucht, alle diese DLLs zu laden, bevor die App eine Codezeile ausführt.

Wie behebe ich das? Ich habe überlegt, eine Hilfe-App zu schreiben, die zuerst startet, die Umgebungsvariablen entsprechend anpasst und die Haupt-App über CreateProcess startet. Das wird funktionieren, da bin ich mir sicher, aber es macht den Entwicklern Schwierigkeiten. Wenn sie die Haupt-App debuggen, werden sie nicht zuerst eine Hilfs-App starten - nicht dass sie das überhaupt können.

Ich habe versucht, die Registrierung App-Pfad-Funktion ohne Erfolg. Das gleiche Problem mit Huhn und Ei wie zuvor.

Was kann ich hier tun?

Antwort

2

[Bearbeiten - nach dem erneuten Lesen der Frage, die ich sehen, dass das Problem, das Sie haben sind, ist, dass die DLLs vor main beginnt geladen werden immer]

Ich vermute, dass diese Bibliotheken in C++ geschrieben sind und Laden der DLLs aus dem Konstruktor einiger Objekte im globalen Gültigkeitsbereich. Dies ist problematisch. Erlauben Sie mir, Yossi Kreinin zu zitieren:

Tun Sie es zuerst in main(). Wenn Sie C++ verwenden, sollten Sie es zuerst vor main() tun, da Leute FP in Konstruktoren globaler Variablen verwenden können. Dies kann erreicht werden, indem die Compiler-spezifische Translationseinheit-Initialisierungsreihenfolge ermittelt wird, eine eigene C/C++ - Startup-Bibliothek kompiliert wird, der Einstiegspunkt einer kompilierten Startup-Bibliothek mit Dingen wie LD_PRELOAD überschrieben und in einem statisch verknüpften Programm überschrieben wird genau dort im binären Bild, mit einer Kodierungskonvention, die dazu zwingt, FloatingPointSingleton :: instance() aufzurufen, bevor FP benutzt wird, oder Leute zu schießen, die Dinge vor main() machen wollen. Es ist ein Kompromiss.

[Original Antwort unten]

Siehe this page für den Suchalgorithmus für das Laden DLLs verwendet. Sie können SetDllDirectory() verwenden, um dem DLL-Suchpfad ein Verzeichnis hinzuzufügen.

Sie sollten auch in der Lage sein, der PATH-Umgebungsvariablen mithilfe von GetEnvironmentVariable() und SetEnvironmentVariable() ein Verzeichnis hinzuzufügen.

Eine andere Option ist das Ändern des aktuellen Arbeitsverzeichnisses in den Ordner mit den DLLs mit SetCurrentDirectory(). Stellen Sie sicher, das Arbeitsverzeichnis nach dem Laden der DLLs wieder zu ändern, wenn Sie jemals Dateien mit relativen Dateinamen laden.

+0

funktioniert Windows hat so etwas wie @load_path in OS X zu setzen? Nämlich zum definierten Suchpfad relativ zur aktuellen DLL oder sowas? Danke. – Royi

2

Meine Empfehlung ist, Delayload-Verknüpfung für die DLLs zu verwenden und SetDllDirectory() früh genug aufzurufen, damit sie sie finden können, wenn die Methoden/Funktionen aufgerufen werden.

+2

Hinweis: Es gibt viele Dinge, die Sie in DllMain nicht tun können, z. B. Laderegistrierungswerte. Aber das Aufrufen von SetDllDirectory ("./dll_dir") * könnte * funktionieren. Nicht getestet. –

3

Ich fand, dass Matthews Antwort für mich arbeitete.

in Visual Studio 2012 goto Ihre Projekteigenschaften und in Konfiguration Eigenschaften-> Linker-> Input-> Delay Loaded Dlls jede DLL-Datei hinzufügen, die Sie nicht wollen, bis sie benötigt werden geladen werden.

Obwohl es nicht mehr braucht, bevor Haupt laufen, dies ist mein Code, um den neuen Suchpfad

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. 
Verwandte Themen