Visual C ++: Liaison d’une DLL à partir d’une autre DLL à l’aide d’un chemin d’access relatif

J’ai la structure de fichier suivante

C:\Application\application.exe C:\Application\plugins\myplugin\myplugin.dll C:\Application\plugins\myplugin\libs\utils.dll 

Ici, application.exe charge myplugin.dll dynamicment via LoadLibrary . Notez que je n’ai aucun contrôle sur application.exe car je développe le plugin uniquement.

Ce que je veux, c’est que myplugin.dll charge libs\utils.dll via un chemin relatif (en utilisant idéalement des liens statiques). En d’autres termes, je ne souhaite pas dépendre de l’emplacement de l’ application.exe . J’ajoute actuellement C:\Application\plugins\myplugin\libs à la variable d’environnement PATH lors de l’installation de myplugin , mais les variables d’environnement ne sont pas la solution idéale et je veux éviter de le faire.

J’espérais pouvoir utiliser des assemblys et des fichiers de configuration pour spécifier le chemin relatif libs\utils.dll dans myplugin.dll . Et j’ai essayé ceci, mais en vain. J’ai ensuite vu quelqu’un mentionner sur StackOverflow que les fichiers de configuration ne fonctionnent que pour les applications (c.-à-d. Les exécutables). Mais comme je l’ai dit plus haut, je n’ai aucun contrôle sur application.exe . Existe-t-il une solution à ce problème apparemment simple qui, à mon avis, sur les systèmes Unix peut être résolu via des voies?

Vous ne pouvez pas établir de lien statique vers un chemin de DLL, relatif ou absolu. La table des importations PE ne contient que des noms de fichiers. C’est pourquoi un chemin de recherche DLL existe pour localiser les DLL.

Si vous souhaitez contrôler où utils.dll est chargé, vous devez le charger dynamicment. myplugin.dll peut récupérer son propre chemin d’access à l’aide de GetModuleFileName() , en utilisant le handle de module transmis à son point d’entrée DllMain() . Il peut ensuite supprimer le nom du fichier du chemin, append le chemin d’access relatif au chemin, puis charger la DLL lorsque cela est nécessaire (pas à l’intérieur même de DllMain() , sinon un blocage / blocage risque de se produire).

Il y a deux façons de gérer cela:

  1. chargez tout dynamicment vous-même:

     #include  #include  #pragma comment(lib, "shlwapi.lib") HINSTANCE hThisDLL = NULL; HMODULE hUtils = NULL; typedef ReturnType __CallingConv (*DllFuncType)(Params); DllFuncType DllFunc = NULL; BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { if (fdwReason == DLL_PROCESS_ATTACH) { hThisDLL = hinstDLL; ... } return TRUE; } ... ReturnType CallDllFunc(Params) { if (!hUtils) { TCHAR szUtilsFileName[MAX_PATH] = {0}; GetModuleFileName(hThisDLL, szUtilsFileName, MAX_PATH); if (!PathRemoveFileSpec(szUtilsFileName)) { // do something... return ...; } if (!PathAppend(szUtilsFileName, TEXT("libs\\utils.dll"))) { // do something... return ...; } hUtils = LoadLibrary(szUtilsFileName); if (!hUtils) { // do something... return ...; } } if (!DllFunc) { DllFunc = (DllFuncType) GetProcAddress(hUtils, "DllFuncName"); if (!DllFunc) { // do something... return ...; } } return DllFunc(Params); } 
  2. lien statique vers tout ce que vous feriez normalement, mais utilisez ensuite la fonctionnalité de chargement différé du compilateur (si supporté) pour pouvoir spécifier le nom de fichier de la DLL dynamicment à l’exécution, mais toujours en liaison statique avec la fonction DLL GetProcAddress() pour vous).

     #include  #include  #include  #pragma comment(lib, "Delayimp.lib") #pragma comment(lib, "shlwapi.lib") HINSTANCE hThisDLL = NULL; FARPROC WINAPI DelayLoadHook(unsigned dliNotify, PDelayLoadInfo pdli) { if ((dliNotify == dliNotePreLoadLibrary) && (strcmpi(pdli->szDll, "utils.dll") == 0)) { TCHAR szUtilsFileName[MAX_PATH] = {0}; GetModuleFileName(hThisDLL, szUtilsFileName, MAX_PATH); if (!PathRemoveFileSpec(szUtilsFileName)) { // do something... return NULL; } if (!PathAppend(szUtilsFileName, TEXT("libs\\utils.dll"))) { // do something... return NULL; } HMODULE hUtils = LoadLibrary(szUtilsFileName); return reinterpret_cast(hUtils); } return NULL; } PfnDliHook __pfnDliNotifyHook2 = DelayLoadHook; BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { if (fdwReason == DLL_PROCESS_ATTACH) { hThisDLL = hinstDLL; ... } return TRUE; } ... ReturnType CallDllFunc(Params) { return DllFuncName(Params); }