Eine Möglichkeit, DLL vom zentralen Repository zu laden

8

Wir haben viele Produkte und es gibt einige gebräuchliche DLLs für die einzelnen Produkte. Im Moment kopieren wir jede gebräuchliche DLL in das bin-Verzeichnis jedes Produkts und behandeln sie als private Assembly. Dies erhöht unnötig die MSI-Größe jedes Produkts und wenn ein Problem in einer DLL auftritt, müssen wir die MSI jedes Produkts erstellen, die die DLL umfasst, und sie bereitstellen.

Gibt es trotzdem eine Anweisung, die Produktanwendung anzuweisen, ein gemeinsames privates Verzeichnis zu verwenden, das zum Laden von DLLs verwendet wird [mit dem Manifestschema ..]? [Hinweis: Das Hinzufügen des privaten Verzeichnisses zu PATH env bietet keine Lösung, als ob eine DLL mit demselben Namen im SYSTEM-Verzeichnis vorhanden wäre, die die Berechtigung über unser privates Verzeichnis übernehmen würde]

-Kartlee

    
Kartlee 28.12.2009, 13:00
quelle

6 Antworten

7

Sie geben nicht an, ob Ihre Umgebung .NET oder reines Win32 ist.

Ich gehe von seinem Win32 aus, denn wenn es .NET gibt, sind die Technologien dafür viel näher bei Dingen wie dem Global Assembly Cache.

In Bezug auf Win32 ist es möglich, Dlls von einem freigegebenen Speicherort auf zwei Arten zu laden:

  • Verwenden Sie LoadLibrary mit expliziten vollständigen Pfaden. Dies bedeutet, dass Sie keine statische Verknüpfung verwenden können - alle DLL-Funktionen, die in allen Produkten verwendet werden, müssen über GetProcAddress aufgerufen werden. Sie können keine C ++ - Klassen aus DLLs importieren, die über LoadLibrary geladen wurden - sie müssen statisch mit der Arbeit verknüpft sein, so dass dieser Ansatz möglicherweise nicht praktikabel ist. Es ist nicht schrecklich schwer, Shim-Header-Dateien zu schreiben, die sich als die Schnittstelle der DLL tarnen und eine Just-in-Time-Dll laden und GetProcAddress, wie für jeden Anruf erforderlich.

  • Die andere Option besteht darin, die DLLs in so genannte "Assemblies nebeneinander" umzuwandeln und sie im WinSxS-Speicher zu installieren. Hab keine Angst vor dem großen Namen. "Assembly nebeneinander" bedeutet "Eine DLL-Datei plus Manifest-Datei mit Versionsinformationen". Jede der verschiedenen Anwendungen würde dann setzen ‚starke Namen‘ - die Versionsinformation enthält - in seine Anwendung Manifest für jeden DLL es verwendet, und die Win32-DLL-Loader werden diese nutzen, die richtige Instanz des gemeinsamen dll vom WinSxS Speicher zu holen. Der grundlegende Prozess ist in dem MSDN-Artikel Richtlinien beschrieben für das Erstellen von Side-by-Side-Baugruppen

Auf Windows-Versionen 6.1 und höher (Windows Server 2008 und die ironisch genannt Windows 7) Anwendungskonfigurationsdateien jetzt tut das Tastelement in Applikationskonfigurationsdateien

Dies bedeutet, dass Sie in der Lage sein sollten, einen Pfad (relativ zu Ihrer Anwendung) zu einem Ordner anzugeben, der dll-Assemblys enthält, die Sie laden möchten.

Ok, ich habe ein paar Tests mit Windows 7 gemacht, und das funktioniert:

Angenommen, Sie haben eine Anwendung app1.exe in \ Programme \ App1 installiert, die von einer gemeinsamen DLL "thedll.dll"

abhängt

Erstellen Sie im Anwendungsordner (\ Programme \ App1) eine Datei App1.exe.config und geben Sie ihr folgenden Inhalt: -

%Vor%

Erstellen Sie jetzt einen Ordner \ Programme \ AcmeCommon genannt, und in ihm einen Ordner acme.thedll und kopieren thedll.dll in \ Programme \ AcmeCommon \ acme.thedll

Auch eine Datei in AcmeCommon \ acme.thedll acme.thedll.manifest genannt schaffen - dies wird die Assembly-Manifest sein, um die Montage der Beschreibung genannte 'acme.thedll'

Der Inhalt von acme.thedll.manifest lautet: -

%Vor%

Jetzt haben wir die gemeinsame DLL an einem gemeinsamen Ort als eine native sxs-Assembly. Wir haben die App, mit einer Konfigurationsdatei, die auf Windows 7 und 2008 Server (und höher) sagen, dass sie nach Assemblys im gemeinsamen Speicherort suchen. Aber die App versucht immer noch, sich als DLL an die DLL zu binden, anstatt über eine Assembly.

Damit die App die Assembly lädt, müssen wir der Anwendung eine Manifestdatei hinzufügen. Wenn Sie Visual Studio verwenden, sind Ihre Anwendungen wahrscheinlich bereits so konfiguriert, dass Manifeste über die Projekteinstellungen für Linker und Manifest-Tools erstellt und eingebettet werden. In diesem Fall ist es am einfachsten, die App über die Assembly zu informieren, indem Sie sie nach dem Hinzufügen des folgenden Codes zu mindestens einer Header- oder c / cpp-Datei im Projekt neu erstellen: -

%Vor%

Wenn Sie eine ältere Build-Umgebung verwenden, in der die Manifeste handgemacht sind, müssen Sie das folgende XML mit app1.exe.manifest im Ordner App1 zusammenführen:

%Vor%

Dies sollte den Kreis schließen: Wenn die App der win32-Loader das Anwendungsmanifest (app1.exe.manifest oder eingebettet als RT_MANIFEST Ressource) und erfahren Sie mehr über die „acme.thedll“ assembly lädt laden. Es lädt auch die Anwendungskonfigurationsdatei (app1.exe.config) und informiert über den privaten Pfad zum Suchen nach Assemblys. Und dann wird "acme.thedll.manifest" geladen und zum Aktivierungskontext der App hinzugefügt. Wenn der Loader dann versucht, "thedll.dll" zu laden, durchsucht er den Aktivierungskontext db, findet ihn in der Assembly acme.thedll und lädt ihn vom Speicherort der Assembly.

    
Chris Becke 29.12.2009 07:09
quelle
1

Wenn Sie über .NET sprechen, können Sie:

  • Laden Sie Ihre DLL direkt aus einer Datenbank mit Assembly.Load(byte[])
  • Unter Verwendung von Assembly.TypeResolve event
  • Mit TypeProvider class
  • Durch Definieren eines Probe-Verzeichnisses in Ihrer Konfigurationsdatei

Wie:

%Vor%     
Rubens Farias 28.12.2009 13:07
quelle
1

Ich folge Chris Antwort. Stellen Sie sicher, dass der Fall in den Manifesten und den Konfigurationen korrekt ist. Sonst werden sie scheitern. Ich konnte die Assembly laden, aber die DLL wurde nicht ausgewählt. In meinem Fall wird eine Windows DLL in system32 statt meiner eigenen mit dem gleichen Namen gewählt. In Dependency Walker wird meine DLL geladen, aber während der Laufzeit wird mit Process Explorer die Windows-Kopie geladen. Irgendwelche Ideen?

    
r590 06.03.2012 00:09
quelle
0

Ich bin mir nicht sicher, ob Sie das suchen, aber wo ich jetzt arbeite, verwenden wir einen gemeinsamen UNC-Pfad für all unsere DLLs.

Wir haben etwas Ähnliches ...

\\ server01 \ productionLibrary für die Produktion liest DLLs, jedes in seinem eigenen Verzeichnis.

und

\\ server01 \ developmentLibrary, die die Produktionsbibliothek spiegelt, und das verwenden die Entwickler bei ihrer Entwicklung.

Wenn wir den Code nach Abschluss des Tests zusammenführen, stellen wir ihn in der Produktionsbibliothek bereit. Alle Projekte verweisen auf die Produktionsbibliothek, wenn sie zur Bereitstellung in MSI-Dateien integriert sind. Unser automatisiertes System erstellt die Projekte in MSIs und überprüft, ob alle DLLs auf die Produktionsbibliothek verweisen. Es besteht also keine Möglichkeit, dass eine Entwicklerkopie versehentlich verwendet wird.

Hoffe, das hilft.

    
Scott Vercuski 28.12.2009 13:09
quelle
0

Ich bin mir nicht sicher, ob ich die Frage richtig verstehe, aber wenn Sie in .Net sind, gibt es einen Global Assembly Cache (GAC): Ссылка

Damit werden die Assemblies zwischengespeichert und ihre Wiederverwendung durch Anwendungen ermöglicht (wie bei .net-Framework). Sie müssen die Assembly einfach bei der Installation bei GAC registrieren, zum Beispiel eine "your framework install" mit allen gängigen Assemblys bereitstellen, und diese kann nur einmal bereitgestellt werden.

    
Kel 28.12.2009 13:16
quelle
0

Das mag Ihnen nicht helfen, aber ... Sie können dlls aus beliebigen Verzeichnissen laden UND sich immer noch auf normale dynamische Verknüpfungen mit ihnen verlassen, solange Sie kontrollieren können, wann die dlls über dynamisches Linking geladen werden, und stellen Sie sicher, dass Sie bereits haben Die DLL wurde explizit mit einem vollständigen Pfad geladen, bevor sie dynamisch geladen wurde.

Dies ist wahrscheinlich nur hilfreich, wenn Sie ein Plugin-System schreiben, in dem Ihre Plugins dynamisch mit DLLs verknüpft sind, die Sie in einem nicht standardmäßigen Verzeichnis behalten möchten. Wenn Sie dann alles über die DLLs wissen, mit denen sie verknüpft sind, können Sie diese DLLs explizit direkt über ihren vollständigen Pfad laden, bevor Sie DLLs (Plugins) laden, die dynamisch von ihnen abhängen. Da die DLL bereits im Speicher ist, wenn Ihr Plugin es finden muss, wird sie die Version im Speicher verwenden. Sie können die explizite Ladung entladen, die Sie vor dem Laden des Plugins ausgeführt haben, und Sie können loslegen.

Leider funktioniert das nicht, wenn Ihre Haupt-EXE DLLs von beliebigen Orten laden muss, da Sie vor dem normalen Dll-Ladevorgang nicht reinkommen können.

    
Len Holgate 30.12.2009 10:47
quelle

Tags und Links