2010-09-30 23 views
11

Szukałem wskazówek, jak to zrobić, ale znalazłem jedynie sposób przekierowania DLL SxS do lokalnego folderu aplikacji. Oto, co chcę osiągnąć: Aplikacja (C++) Application.exe jest połączona z DLL, Plugin.DLL (projekt zależny). Ta biblioteka DLL nie znajduje się w katalogu aplikacji, ale w podfolderze o nazwie "wtyczki". Ponieważ biblioteka DLL jest statycznie połączona, aplikacja spróbuje załadować ją z folderu aplikacji.Zmiana ścieżki wyszukiwania DLL dla statycznie połączonych bibliotek DLL

Czy istnieje sposób, w jaki mogę zmienić ścieżkę wyszukiwania dla tej konkretnej biblioteki DLL? Albo poprzez manifesty, albo konfiguracje łączników VS2008?

Odpowiedz

17

Moja pierwsza myśl to, że jeśli statycznie łączysz dll, to nie jest to wtyczka. Po prostu umieść bibliotekę DLL w folderze EXE i skończ z nią. To jest konfiguracja wdrażania obsługiwana przez okna dla statycznie załadowanych bibliotek DLL.

Powiedziawszy, istnieją sposoby osiągnięcia tego, co chcesz. Są one jednak w większości głupie lub skomplikowane bez ważnego powodu: dostępne są następujące opcje:

  • Nie statycznie łącz. Użyj funkcji LoadLibrary ("plugins/Plugin.dll") & GetProcAddress, aby uzyskać dostęp do zawartości wtyczki.
  • Dodaj "ścieżkę do folderu wtyczek" do zmiennej środowiskowej PATH systemów.
  • Użyj mechanizmu opóźnienia obciążenia, aby opóźnić dostęp do funkcji wtyczek, ustaw custom helper function, który może załadować bibliotekę dll za pomocą dostarczonej ścieżki.
  • Zmień folder wtyczek w zespół (tworząc plik .manifest zawierający listę wtgin.dll). Dodaj "wtyczki" jako zależny zespół do swojej aplikacji. Teraz będzie wyglądać w folderze wtyczek.
  • Podziel swoją aplikację na kod pośredniczący i dynamicznie ładowaną część. W wywoływaniu exe wywołaj SetDllDirectory, aby wskazał folder wtyczki, a następnie wywołaj LoadLibrary przekazując pełną ścieżkę do "appstub.dll".

Aby włączyć folder, z jednym lub więcej bibliotek DLL w produkt „montaż”, wystarczy dodać plik do folderu z folderów name.manifest.

Więc plugins.manifest: -

<assembly manifestVersion="1.0"> 
    <assemblyIdentity type="Win32" name="Plugins" version="1.0.0.0" processorArchitecture="x86" /> 
    <file name="Plugin.dll"/> 
</assembly> 

Jest to bardzo dobry pomysł, aby upewnić się, że folder i nazwa DLL jest inna jakby nazwa dll jest montaż okien nazwa zaczyna patrząc na jego wbudowania plik manifestu dla informacji o złożeniu.

Zakładając, że używasz programu Visual Studio 7 lub nowszego, do pliku .c/.cpp lub. Dodano następującą dyrektywę.Plik h w projekcie będą następnie dokonać próby aplikacji ładowania bibliotek DLL z zespołu, a nie tylko lokalnego katalogu:

#pragma comment(linker, "/manifestdependency:\"name='Plugins' "\ 
         "processorArchitecture='*' version='1.0.0.0' "\ 
         "type='win32'\"") 
+0

Dzięki - skorzystałem z metody GetProcAddress, ponieważ nie mogłem zrozumieć, jak musi wyglądać manifest, aby działało podejście "fałszywy montaż". Na szczęście działa to dobrze w całej architekturze. – Oliver

+1

Nie potrzebujesz 'SetDllDirectory' do ładowania opóźnienia; istnieje hook '__pfnDliNotifyHook2', dzięki czemu możesz wywołać' LoadLibrary (". \\ plugins \\ PluginX.dll") 'bezpośrednio. Pomysł '% PATH%' jest trochę kruchy, ponieważ jest on raczej niski na liście lokalizacji do sprawdzenia. – MSalters

+0

dzięki. Nigdy osobiście nie używałem opóźnienia ładowania, więc założyłem, że SetDllDirectory będzie sposobem na dostrojenie. –

5

rozszerzania i detailing Chris' proposal danego „Zgromadzenie” podkatalogu: Uwaga


Side Chris ma również dwa znakomite upy aktualizujące więcej szczegółów:


MS docs

To jest rzeczywiście nazwać "Private Assembly" i MS docs wyjaśnić to w ten sposób:

zespoły prywatne są zainstalowane w folderze struktury katalogu aplikacji. Zazwyczaj jest to folder zawierający plik wykonywalny aplikacji . Prywatne zespoły mogą być rozmieszczone w tym samym folderze co aplikacji, w folderze o takiej samej nazwie jak zespół lub w określonym podkatalogu językowego o tej samej nazwie jako zespołu.

Na przykład (...)

Appdir\Microsoft.Tools.Pop\Microsoft.Tools.Pop.MANIFEST: Manifest jest wdrażany jako osobny plik w podfolderze posiadającego nazwę Zgromadzenia.

(...)

zespoły prywatne mogą być instalowane za pomocą dowolnej metody instalacji, które można skopiować pliku Zgromadzenia do tego folderu, takich jak komenda xcopy.

Przykład

Masz jesteś wierny stary plik wykonywalny w folderze C:\Test\Program\app.exe program, a chcesz - at Load-Time - załaduj plik DLL z Plugins podfolderu, tj C:\Test\Program\plugins\tool1.dllbez niepożądanym PATH lub jakiekolwiek inne rzeczy.

Musisz:

  • Kompilacja app.exe z:

    #pragma comment(linker, "/manifestdependency:\"name='Plugins' version='1.0.0.0' type='win32'\"") 
    // name, type and version seems to be the minimum info to get away with 
    

    Uwaga: Kompilacja/Łączenie w ten, a nie za pomocą manifestu zewnętrznej (app.exe.manifest) jest wymagana mój system testowy, nie dowiedziałem się jeszcze dlaczego.(* A)

    Co również działa jednak jest osadzanie/scalania plik manifestu wymienione poniżej do pliku wykonywalnego z narzędziem mt, zamiast z Pragma łącznikową. (Configuration > Manifest Tool > Additional Manifest Files)

  • put tool1.dll intro z plugins podfolder

  • dodać plik plugins.manifest do podfolder wtyczek, czyli C:\Test\Program\plugins\plugins.manifest i że wygląda tak:

wtyczek. manifest:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> 
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> 
    <assemblyIdentity 
          type="win32" 
          name="Plugins" 
          version="1.0.0.0" 
      /> 
    <file name="tool1.dll"/> 
</assembly> 

To wszystko. Uruchamianie app.exe automatycznie znajdzie dll w podfolderze w Czasie ładowania.


(* a): Scalanie ten plik manifestu działa, ale nie można używać, jako jedynego zewnętrznego pliku manifestu, i podejrzewam, że to dlatego, że brakuje wszystkich innych oczywistego informacji system build już umieszcza się twój plik wykonywalny!

+0

Numpy wiki @ https://github.com/numpy/numpy/wiki/windows-dll-notes również ma ładne napisać o tym –

+0

Zewnętrzny plik manifestu jest używany tylko Myślę, że jeśli nie ma osadzonego pliku manifestu. Kompilator VS teraz domyślnie osadza manifesty, więc ładowanie manifestów w czasie pracy jest możliwe tylko wtedy, gdy usuniesz je najpierw. –

Powiązane problemy