【发布时间】:2019-08-25 02:11:53
【问题描述】:
我有一个包含两个 DLL 的解决方案。第一个是“主”DLL。它恰好是一个 ODBC 驱动程序,但我认为这对于这个问题并不重要。
第二个 DLL 包含第一个的所有 UI 逻辑。由于并不总是需要 UI,我想使用 /DELAYLOAD 功能,它明确表示:
DLL 的延迟加载可以在构建过程中指定 .EXE 或 .DLL 项目。
主 DLL 的项目正确地引用了 UI 项目。如果我不使用/DELAYLOAD,一切正常。这两个 DLL 将安装到同一个目录中,所以我认为从另一个 DLL 中加载一个 DLL 应该很容易。但显然不是。
一旦调用 UI DLL 中的第一个函数,应用程序(在我的例子中是任何 ODBC 客户端)就会崩溃。
GetLastError() 产生 126,这显然意味着在任何搜索路径中都找不到目标 DLL。
确实,根据this answer LoadLibrary() 确实查看了调用可执行文件的目录,但没有查看当前执行的DLL之一。我假设/DELAYLOAD 也只是在后台使用LoadLibrary(),对吗?
如果我将可执行文件复制到我的驱动程序的安装目录中,它可以正常工作,这证明了我的假设,它只是不在当前 DLL 的目录中查找。
除此之外,我还可以通过调用使其运行
LoadLibrary(L"C:\\absolute\\path\\to\\UI.dll");
就在加载 UI DLL 的第一个函数之前。 我还能够使用
以编程方式确定此路径wchar_t buffer[512];
GetModuleFileName(hThisDLL, buffer, sizeof(buffer));
但是我必须用这个逻辑覆盖每一个 UI 调用。所以我不会再看到/DELAYLOAD 比使用LoadLibrary() 和GetProcAddress() 的“老派”方式有太多优势了。
问题
有没有简单的方法让/DELAYLOAD从同一目录下的另一个DLL中找到目标DLL?
【问题讨论】:
-
写自己的
__pfnDliNotifyHook2并处理dliNotePreLoadLibrary -
在调用 UI DLL 的任何导出之前,将
/DELAYLOAD与对 SetDllDirectoryW 的调用组合以将 UI DLL 的目录添加到搜索路径。不需要其他任何东西。 -
使用AddDllDirectory(而不是SetDllDirectory)和LoadLibraryEx添加额外的搜索路径来加载DLL而不影响以后的DLL加载搜索路径。
标签: c++ visual-studio winapi dll