C ++: Manifestiert und lädt dynamisch DLLs aus verschiedenen Verzeichnissen

8

Lange Geschichte von dem, was ich erreichen möchte

Ich arbeite an einem Programm, das DLLs dynamisch als Plugins lädt. Ich kompiliere das Programm unter Verwendung von Microsoft Visual C ++ 2008. Nehmen wir dennoch an, dass jede Visual C ++ - Version, mit der Qt funktioniert, unterstützt werden sollte. Das Programmverzeichnis-Layout folgt:

%Vor%

program.exe entdeckt alle Plugin-DLL-Dateien, führt LoadLibrary () auf ihnen aus und ruft eine bestimmte Signaturfunktion auf, um herauszufinden, ob es sich tatsächlich um ein Plugin handelt oder nicht. Dies funktioniert sehr gut auf Computern, auf denen vcredist für MSVC90 installiert ist. Damit das Programm auf allen Computern funktioniert, muss es natürlich mit den msvc * .dll-Dateien und der entsprechenden Manifest-Datei neu verteilt werden. Für Qt-DLLs muss der Redist ebenfalls ausgeführt werden.

Nun habe ich cmake eingerichtet, um automatisch die entsprechenden Redist-DLLs zu kopieren und sie abhängig von der ausgewählten Visual Studio-Version zu manifestieren. Der Einfachheit halber nehmen wir an, dass ich mit MSVC90 arbeite. Wenn der Redist in das Programmverzeichnis kopiert wird, sieht das Layout so aus:

%Vor%

Was den Fehler in der Manifestdatei betrifft: Ссылка

Das Problem

Das Programm mit diesem Layout funktioniert jetzt auf Computern, auf denen der Redist nicht installiert ist, aber die Plugins werden nicht geladen. Um die Plugins zum Laden zu bringen, muss ich einen der folgenden Schritte ausführen:

  1. Kopieren Sie die Manifestdatei in das Verzeichnis plugins/ . Entfernen Sie alle Verweise auf msvc * .dll-Dateien aus der Manifestdatei. Das funktioniert, aber es ist nicht nett, weil ich verschiedene Versionen der bearbeiteten Manifest-Dateien abhängig von der Version des verwendeten MSVC unterstützen müsste. Außerdem habe ich keine Ahnung, ob dies nicht mit Visual Studio anders als 2008 bricht.
  2. Kopieren Sie den gesamten Redist in das Verzeichnis plugins/ . Dies erfordert keine Änderungen an der Manifest-Datei, aber nun versucht program.exe dummerweise die msvc * .dll-Dateien zu laden, da sie denken, dass sie Plugins sind. Das scheitert natürlich, so dass kein großer Schaden angerichtet wird. Der andere Nachteil ist, dass die Größe des Programmpakets um mehr als 1 MB wächst. Beide Probleme sind jedoch etwas, mit dem ich leben kann.
  3. Kompiliere Plugins mit / MT Switch. Kurze Tests haben gezeigt, dass dies tatsächlich funktioniert, aber ich bin mir nicht sicher, ob es in der Zukunft nichts brechen wird, wenn sowohl Qt als auch program.exe / MD sind.

Die Frage (n)

Was ist die beste Lösung? Was ist die richtige Lösung? Wenn es mehr als eine richtige Lösung gibt, welche ist die beste Praxis? Bin ich die erste Person, die das jemals versucht hat?

Update 1 (18 Nov. 2012)

Während die Frage unbeantwortet bleibt, habe ich mich für den Weg entschieden, der am wenigsten Kopfschmerzen verursacht. Bis jetzt habe ich Lösung Nummer 1 benutzt und ich habe beschlossen, dabei zu bleiben. Wenn CMake erkennt, dass der Benutzer eine andere MSVC-Version als 2008 verwendet, wird eine Warnmeldung angezeigt, dass das automatische Packen nicht vollständig unterstützt wird.

    
ZalewaPL 04.11.2012, 21:59
quelle

3 Antworten

1

Sie können "LoadLibrary" vollständige Dateipfade bereitstellen, damit Sie Ihre Plugins mit ihren Pfaden laden können. Ich habe dieses genaue Layout verwendet, um mehrere Versionen derselben Bibliothek aus Unterverzeichnissen der aktuellen DLL in Visual Studio 2005 zu laden.

Sie müssen zuerst den aktuellen Pfad der aktuellen DLL mit:

abrufen %Vor%

Obwohl, wenn Ihre Programm.exe diese Plugin-Dateien bereits entdeckt, würde ich annehmen, dass Sie bereits Zugriff auf ihre vollständigen Pfade haben.

    
MultiMat 27.11.2014 11:41
quelle
0

Wenn Ihr Zielbetriebssystem _WIN32_WINNT & gt; = 0x0502 hat, können Sie die Funktion

verwenden %Vor%

bevor Sie die Plugins laden.

Geben Sie den Pfad zum Hauptprogrammordner ein.

Der Aufruf überschreibt die Systemladungsreihenfolge:

  1. Das Verzeichnis, aus dem die Anwendung geladen wurde.
  2. Das Verzeichnis, das durch den Pfad in SetDllDirectory () angegeben wurde.

Sie können die Funktion also nach dem Start der Anwendung aufrufen. Es ist in allen Fällen sicher. Viel Glück!

    
Brian Haak 07.11.2012 11:00
quelle
0

Sie können Hardlinks zu VC-DLLs mit der Funktion CreateHardLink () beim Installationsprozess erstellen. Bei der Methode (1), die Sie beschrieben haben, kann es Probleme mit verschiedenen Kopien von VCRT-DLLs geben. Hardlinks oder SetDllDirectory () scheint die beste Lösung zu sein.

Mischen Sie nicht in einem einzigen Prozess statische und dynamische Verbindung zu MSVCRT - es gibt Ihnen IMMER Probleme!

    
Brian Haak 07.11.2012 15:56
quelle