我是否可以获取单独的 DLL 来单独解析其导入的 DLL
Can I get separate DLLs to resolve their imported DLLs separately?
我有一些DLL是这样安排的:
-
lib.dll
- 具有链接到的导入库的第三方 DLL -
plugin.dll
- 链接到lib.dll
的DLL,一个旨在加载到具有LoadLibrary
的主机程序中的插件 -
otherplugin.dll
- 另一个链接到lib.dll
的插件 DLL -
otherlib.dll
- 其他插件的lib.dll
副本
(这些只是带有一些导出函数的普通 DLL - 我没有使用 COM 或任何东西。
在我的测试设置中,如果我使用 LoadLibrary
加载plugin.dll
,然后使用 LoadLibrary
加载otherplugin.dll
,似乎它们都共享同一个加载的lib.dll
副本。但我实际上需要otherplugin.dll
来加载otherlib.dll
- 我不希望共享库。
我可以这样做吗?(理想情况下,无需重新编译lib.dll
。
允许此操作的技术称为应用程序隔离。它的工作方式是让开发人员使用清单文件将其 dll 排列到并排程序集中。
有关官方文档,请阅读 MSDN 上的独立应用程序。
或者,这可以在没有所有这些的情况下工作,假设您实际上是通过 LoadLibrary
显式加载"lib.dll"。
首先,请注意,当 Dll 调用 LoadLibrary 时,不会搜索 DLL 自己的文件夹。如果查看 MSDN 上LoadLibrary
的文档,您将看到应用程序可执行文件文件夹是首选搜索位置。所以你需要做的第一件事是在加载插件之前调用SetDllDirectory
.dll这样它就可以真正找到自己的"lib.dll"副本。
接下来 - 请注意,加载库搜索路径仅在传递相对路径时使用。
因此,如果您首先修复 DllDirectory 和 LoadLibrary "插件.dll",然后调用 LoadLibrary,将完全限定的路径传递给您自己的 Lib.dll 副本,那么插件.dll将使用搜索路径加载自己的版本,并且您的应用程序将显式加载自己的版本。
还有另一种选择:将 DLL 设置为延迟加载,并使用延迟加载 DLL 导入挂钩显式加载所需的 DLL。
在解析延迟加载的DLL时,通常系统(尽管我不确定是哪一部分 - 大概是CRT?(会发现已经加载了一个plugin.dll
并向其分发另一个句柄。但是使用延迟加载 DLL 钩子,您可以让它加载另一个带有LoadLibrary
的 DLL - 在这种情况下是共享 DLL 的插件特定副本。提供完整路径,因此LoadLibrary
不可能返回现有 DLL 的句柄。
为此,请将 DLL 的 H实例存储在 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 做同样的事情......
- 如何在C++中从两个单独的for循环中添加两个数组
- 挂起和取消挂起一个文件DLL
- std::threads可以从Windows DLL中的全局变量创建/销毁吗?
- 导入库可以跨dll版本工作吗
- 用C++在单独的头文件中完成函数体
- 从C++dll访问C#中的一行主要参数
- 链接到自行创建的dll失败
- 类模板的成员功能的定义在单独的TU中完全专业化
- 为什么使用 P/Invoke 调用 dll 时,某些计算机中的 LoadLibrary 失败?
- 如何使用单独文件中的派生类访问友元函数对象
- 在调用FreeLibrary后,释放动态链接到具有相同版本的CRT堆的DLL的内存
- CoInitialize()在单独的线程上崩溃而不返回
- 如何指定我希望我的LIB链接到的DLL文件?-Visual Studio 2019
- 如何将图像传输到c++(dll)中的缓冲区,然后在c#的缓冲区中读/写
- 将 std::cout 从单独线程中的 DLL 重定向到 QTextEdit
- 如何将我的C++DLL包含在一个单独的项目中
- 在两个单独的应用程序之间共享 dll 中的堆内存
- 将Qt DLL保存在单独的文件夹中
- 我是否可以获取单独的 DLL 来单独解析其导入的 DLL
- 我怎么能运行一个.exe与dll在单独的目录