2013-01-11 8 views
6

Przy użyciu Visual Studio C++ V10, staram się dowiedzieć, jak zbudować DLL i rozwiązać konflikt nazw plików DLL. Oto szczegóły.Unmanaged C++ DLL o tej samej nazwie współistnieją w tym samym procesie

Firma S wysyła produkt o nazwie M.EXE. Załóżmy, że M.EXE jest zainstalowany w \S\BIN\M.EXE. Firma S statycznie łączy się z biblioteką DLL o nazwie U.DLL, która jest instalowana w wersji \S\BIN\U.DLL. U.DLL zawiera kod open source i jest zbudowany z opcjami kompilatora Visual C++ /Zc:wchar_t-, który nie rozpoznaje wchar jako natywnego typu.

Firma C wysyła bibliotekę DLL o nazwie O.DLL i publikuje interfejsy API dla tej biblioteki DLL oraz wysyła bibliotekę importowania dla O.DLL. Załóżmy, że O.DLL jest zainstalowany w \C\BIN\O.DLL. O.DLL statycznie łączy się z biblioteką DLL o nazwie U.DLL, która jest instalowana w wersji \C\BIN\U.DLL. U.DLL jest zbudowany na tym samym kodzie open source, ale jest zbudowany z opcjami kompilatora Visual C++ /Zc:wchar_t, który rozpoznaje wchar_t jako natywny typ.

Idealnie firma C i firma S zgodziłaby się zbudować U.DLL przy użyciu tych samych opcji Visual C++, ale to nie jest możliwe.

M.EXE z firmy S jest rozszerzalny, że mogę stworzyć własną bibliotekę DLL w niezarządzanych C++, nazywają to NODE.DLL że M.EXE wywoła jeśli ustawi wszystko poprawnie. Chciałbym zbudować NODE.DLL tak, że statycznie linki do O.DLL z firmy C. Ale problemem jest to, że raz M.EXE działa, załadował bibliotekę U.DLL z \S\BIN, a symbole z \S\BIN\U.DLL są nieco inne niż te w \C\BIN\U.DLL, ze względu na to, w jaki sposób każda firma zbudowała U.DLL. Tak więc, gdy M.EXE próbuje załadować NODE.DLL, nie powiedzie się, ponieważ gdy NODE.DLL ładuje O.DLL, który potrzebuje U.DLL, symbole potrzebne od \C\BIN\U.DLL nie istnieją, ponieważ system Windows widzi U.DLL jako już załadowany.

Schemat sytuacja przedstawia się następująco:

M.EXE static link to -> \S\BIN\U.DLL 
M.EXE dynamic link to -> NODE.DLL 
NODE.DLL static link to O.DLL 
O.DLL static link to \C\BIN\U.DLL 

efekcie, trzeba zarówno \S\BIN\U.DLL i \C\BIN\U.DLL współistnieć na tym samym miejscu procesu, i M.EXE wykorzysta wersją U.DLL i O.DLL użyciu jego wersja U.DLL.

Należy pamiętać, że nie mam opcji odbudować M.EXE lub O.DLL, aby zmienić sposób ich ładowania U.DLL. Pochodzą od stron trzecich, więc nie można zmienić linkowania statycznego. Nie mam również możliwości użycia LoadLibrary na O.DLL, ponieważ jest to biblioteka C++, dostarczana z biblioteką importu.

wierzę, że manifesty można stosować tak, że kiedy budować NODE.DLL, który jest połączony z O.DLL statycznie, ustawić rzeczy w manifeście NODE.DLL tak że O.DLL ładuje własną kopię U.DLL który jest zainstalowany w \C\BIN\U.DLL. Po prostu nie mogę wymyślić, jak to zrobić. Idealnie nie chciałbym modyfikować manifestu O.DLL, ale jeśli to jedyne rozwiązanie, będę z tym żyć.

+0

DLL's, DLL's ALLERWHERE! (Przepraszam, nie mogłem się powstrzymać) Cześć i witaj. – doge

+0

Zasadniczo problem polega na tym, że 'O.DLL' w IAT określa, że ​​łączy się z' U.DLL', bez zastrzeżeń. – MSalters

Odpowiedz

3

Można mieć wiele bibliotek DLL z tego samego pliku w tym samym procesie, ładując jeden lub więcej z nich ścieżek bezwzględnych. To wymaga dynamicznego ładowania biblioteki DLL, ale zachowanie jest poza tym identyczne.

Zamiast łączenia w trakcie procesu kompilacji, musisz std::string moduleName = appPath + "\s\bin\u.dll"; LoadModule(moduleName.c_str()). Ponieważ jest to jednoznaczne, jakie załadowane są biblioteki DLL, pozwala załadować wiele z nich o "tej samej nazwie".

Po załadowaniu modułu można przypisać każdą z niezbędnych funkcji do wskaźników funkcji, a następnie zawijać je lub użyć legalnego, ale mało używanego, syntax of calling functions pointers as normal functions (funcPtr(params)).

Jeśli korzystasz z najnowszej wersji systemu Windows, możesz użyć manifestów DLL, aby wzmocnić wersjonowanie/nazewnictwo w module i spowodować, że EXE załaduje inną bibliotekę DLL niż zwykle. Nie jestem obeznany z tym, jak dokładnie to się stanie, chociaż jest to udokumentowane w MSDN (i prawdopodobnie również tutaj).

+0

Nie jest to opcja, ponieważ nie mam możliwości odbudować M.EXE lub O.DLL. Pochodzą z różnych stron trzecich. – Irv

+0

Jeśli jeden z tych modułów korzysta z częściowej lub bezwzględnej ścieżki lub używa dynamicznego ładowania, możliwe, że będziesz w stanie przetrwać. W przeciwnym razie manifesty będą twoją jedyną szansą. – ssube

+0

Uważam, że manifesty są jedynym wyborem. Chciałbym wiedzieć, co umieścić w manifeście, żeby wszystko działało. Zarówno M.EXE, jak i O.DLL są zbudowane przy użyciu bibliotek importu, które następnie ładują U.DLL przy użyciu normalnych reguł ładowania DLL. Każda firma umieszcza własną wersję U.DLL w swoim własnym katalogu BIN. Kiedy uruchamiany jest M.EXE, odbiera on swoją kopię pliku U.DLL. Podczas pisania standardowego EXE, który wykorzystuje O.DLL, odbiera swoją kopię U.DLL. – Irv

0

Spróbuj użyć funkcji LoadLibrary i GetProcAddress. Będzie to wymagało zrestrukturyzowania twojego kodu, aby wszędzie korzystać ze wskaźników funkcji. Zobacz:

MSDN web page for LoadLibrary

+0

Nie jest to opcja, ponieważ nie mam możliwości odbudować M.EXE lub O.DLL. Pochodzą z różnych stron trzecich. – Irv

1

można rozwiązać DLL source programowo w runtiome za pomocą opcji/delayload łącznikową (Linker/input/Delay Załadowane DLL w właściwości projektu VS) wraz z hakiem niestandardowej. W jednym z plików źródłowych musisz zdefiniować i zarejestrować funkcję przechwytywania opóźnienia. W funkcji obsługi powiadomień dliNotePreLoadLibrary funkcji hook, po prostu wywołaj LoadLibrary z jawną ścieżką do żądanej biblioteki DLL, a następnie przekaż HMODULE DLL z powrotem do kodu opóźnienia. Kod opóźnienia rozdzieli zaimportowane funkcje na bibliotekę DLL, którą podasz, niezależnie od tego, czy inna biblioteka DLL o tej samej nazwie została już załadowana do procesu.

Z góry mojej głowy, twój hak będzie wyglądać mniej więcej tak (gdzie MyCustomLoadLibrary należy zastąpić kodem wywołującym LoadLibrary pełną ścieżką do pożądanej biblioteki DLL w przypadku powodującym konflikt lub po prostu niewykwalifikowaną nazwą pliku) :

#include <delayimp.h> 
FARPROC WINAPI MyDliNotifyHook(unsigned dliNotify, PDelayLoadInfo pdli) 
{ 
    if(dliNotify == dliNotePreLoadLibrary) 
    return (FARPROC)MyCustomLoadLibrary(pdli->szDll); 
    return NULL; 
} 
extern "C" PfnDliHook __pfnDliNotifyHook2 = MyDliNotifyHook; 
+0

Działa to tylko wtedy, gdy NODE.DLL jest linkiem prowadzącym do konfliktu DLL. Po ponownym przeczytaniu twojego pytania widzę, że mówisz, że jest to jedna z zależnych bibliotek DLL, które prowadzą do konfliktu DLL. W takim przypadku będziesz musiał programowo rozwiązać tabelę adresów importowanych zależnych bibliotek DLL. Nie jest to trudne, ale opisywanie kroków tutaj jest zbyt skomplikowane. –

+0

"programowo rozwiń tabelę adresów importowanych zależnych bibliotek DLL": czy możesz podać wskaźnik, ale czy mogę przeczytać więcej? – harper

+1

Istnieją dwa przypadki: przypadek, w którym program ładujący może pomyślnie rozwiązać cały import (aczkolwiek do niewłaściwej biblioteki DLL); oraz przypadek, w którym program ładujący nie może rozwiązać importu. Jeśli twoja sprawa jest pierwsza, mogę podać kilka wskazówek. Jeśli twoja sprawa jest tym drugim, musisz zasadniczo odtworzyć kod programu ładującego systemu Windows (rozwiązywanie importów i stosowanie poprawek, a następnie wywoływanie funkcji punktu wejścia). Jest niewiele cennej dokumentacji i nie znam żadnych publicznych źródeł informacji. Nie dla osób o słabym sercu, ale jest to możliwe: Zrobiłem to z powodzeniem. –

0

Masz szczęście, że U.DLL jest Open Source. Będziesz musiał zbudować wersję obsługującą funkcje zarówno dla funkcji /Zc:wchar_t- i /Zc:wchar_t. Pierwsza opcja określa tylko wchar_t- jako unsigned short. Otrzymasz mnóstwo ostrzeżeń linkera dla duplikatów symboli, dla każdej funkcji, która nie ma argumentu wchar_t, ale w przeciwnym razie skończysz z grubszą biblioteką DLL.

Pamiętaj, że jeśli istnieją zmienne globalne lub static przy użyciu wchar_t, będziesz mieć również dwie kopie tych zmiennych. Ale miałbyś taki sam efekt, gdyby w jednym procesie podwoziono dwie kopie U.DLL.

Powiązane problemy