我有以下文件结构
C:\Application\application.exe
C:\Application\plugins\myplugin\myplugin.dll
C:\Application\plugins\myplugin\libs\utils.dll
此处application.exe
通过myplugin.dll
动态加载LoadLibrary
。请注意,我无法控制application.exe
,因为我只开发插件。
我想要的是通过 相对 路径(理想情况下使用静态链接)myplugin.dll
加载libs\utils.dll
。也就是说,我不想依赖application.exe
的位置。我在安装C:\Application\plugins\myplugin\libs
时最初将PATH
添加到myplugin
环境变量,但环境变量不是理想的解决方案,我希望避免这样做。
我希望我可以使用程序集和配置文件来指定libs\utils.dll
中的相对路径myplugin.dll
。我试过这个,但无济于事。然后我看到有人在StackOverflow上提到配置文件仅适用于应用程序(即可执行文件)。但正如我上面所说,我无法控制application.exe
。有没有一个解决这个看似简单的问题的解决方案,我认为Unix系统可以通过rpath解决?
答案 0 :(得分:3)
您根本无法静态链接到DLL路径,相对或绝对。 PE导入表仅包含文件名。这就是DLL search path存在以找到DLL的原因。
如果要控制加载utils.dll
的位置,则必须动态加载。 myplugin.dll
可以使用传递到其GetModuleFileName()
入口点的模块句柄,使用DllMain()
检索自己的路径。然后它可以从路径中删除文件名,附加路径的相对路径,然后在需要时加载DLL(不在DllMain()
本身内部,否则可能发生死锁/崩溃)。
有两种方法可以解决这个问题:
自己动态加载所有内容:
#include <windows.h>
#include <shlwapi.h>
#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);
}
静态链接到你通常会做的所有事情,但是然后利用编译器的delay load功能(如果支持),这样你就可以在运行时动态指定DLL的文件名,但仍然静态链接到DLL函数本身(延迟加载机制会为你调用GetProcAddress()
。
#include <windows.h>
#include <shlwapi.h>
#include <delayimp.h>
#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<FARPROC>(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);
}