我有一些像这样排列的DLL:
lib.dll
- 第三方DLL,其中包含您链接到plugin.dll
- 一个链接到lib.dll
的DLL,一个旨在通过LoadLibrary
加载到主机程序中的插件other\plugin.dll
- 另一个链接到lib.dll
other\lib.dll
- otherplugin的lib.dll
(这些只是普通的DLL,带有一些导出的函数 - 我没有使用COM或其他东西。)
在我的测试设置中,如果我使用LoadLibrary
加载plugin.dll
,然后使用LoadLibrary
加载other\plugin.dll
,则它们似乎都共享相同的加载副本lib.dll
。但实际上我需要other\plugin.dll
来加载other\lib.dll
- 我不希望共享库。
我可以这样做吗? (理想情况下无需重新编译lib.dll
。)
答案 0 :(得分:3)
允许此操作的技术称为应用程序隔离。它的工作方式是让开发人员使用清单文件将他们的dll安排到Side by Side程序集中。
在MSDN上阅读Isolated Applications以获取官方文档。
或者,这可以在没有这一切的情况下工作,假设你实际上正在加载" lib.dll"明确地通过LoadLibrary
。
首先,请注意,当Dll调用LoadLibrary时,不会搜索DLL自己的文件夹。如果您在MSDN上查看LoadLibrary
的文档,您将看到应用程序可执行文件夹是首选搜索位置。因此,您需要做的第一件事是在加载Plugin.dll之前调用SetDllDirectory
,以便它实际上可以找到自己的" lib.dll"。
下一步 - 请注意,LoadLibrary搜索路径仅在传递相对路径时使用。
所以,如果你首先修复DllDirectory和LoadLibrary" Plugin.dll"然后调用LoadLibrary,将完全限定的路径传递给您自己的Lib.dll副本,然后plugin.dll将使用搜索路径加载自己的版本,您的应用将显式加载自己的版本。
答案 1 :(得分:1)
还有另一种选择:将DLL设置为延迟加载,并使用the delay load DLL import hook显式加载所需的DLL。
当解决延迟加载的DLL时,通常系统(虽然我不确定哪个部分 - 可能是CRT?)会发现已经加载了plugin.dll
并分发了另一个句柄它。但是使用延迟加载DLL挂钩,您可以使用LoadLibrary
加载另一个DLL - 在这种情况下是共享DLL的插件特定副本。提供完整路径,因此LoadLibrary
无法返回现有DLL的句柄。
为此,请将DLL的HINSTANCE存储在DllMain
。
static HINSTANCE g_hinstDLL;
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) {
if (fdwReason == DLL_PROCESS_ATTACH)
g_hinstDLL = hinstDLL;
return TRUE;
}
并有一个合适的延迟加载钩子,可以监视dliNotePreLoadLibrary
。
static FARPROC WINAPI DliHook(unsigned dliNotify, PDelayLoadInfo pdli) {
if (dliNotify == dliNotePreLoadLibrary) {
if (strcmp(pdli->szDll, "plugin.dll") == 0) {
char path[MAX_PATH];
GetModuleFileNameA(g_hinstDLL, path, sizeof path);
PathRemoveFileSpecA(path);
PathAppendA(path, "plugin.dll");
HMODULE hModule = LoadLibraryA(path);
return (FARPROC)hModule;
}
}
return 0;
}
const PfnDliHook __pfnDliNotifyHook2 = &DliHook;
(最后我不得不放弃这整个方法 - lib.dll
似乎假设每次进程只会加载一次,而不是不合理地加载,并且在多次加载时以各种方式与自身冲突。原则上可能是可解的,但我希望我只能为Linux和OS X做同样的事情......)