我有两个DLL的解决方案。第一个是“主” DLL。它碰巧是ODBC驱动程序,但是我认为这对于这个问题并不重要。
第二个DLL包含第一个的所有UI逻辑。由于并非总是需要UI,因此我想使用/DELAYLOAD
功能,该功能明确表示:
可以在构建DLL的过程中指定DLL的延迟加载。 .EXE或 .DLL 项目。
主DLL的项目正确引用了UI的项目。如果我不使用/DELAYLOAD
,那么一切都很好。这两个DLL将被安装到同一目录中,因此我认为从另一个内部加载一个DLL应该很容易。但显然不是。
一旦从UI DLL调用了第一个函数,应用程序(在我的情况下为任何ODBC客户端)就会崩溃。
GetLastError()
产生126,这显然意味着在任何搜索路径中都找不到目标DLL。
确实,根据this answer LoadLibrary()
确实可以查看正在调用的可执行文件的目录,而不是当前执行的DLL之一。我假设/DELAYLOAD
也在幕后使用LoadLibrary()
,对吗?
如果将可执行文件复制到驱动程序的安装目录中,则可以正常运行,这证明了我的假设,即该可执行文件不在当前DLL的目录中。
Appart之后,我也可以通过调用使其运行
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?
答案 0 :(得分:1)
有。我的建议是创建一个延迟加载失败钩子函数。
https://docs.microsoft.com/en-us/cpp/build/reference/failure-hooks?view=vs-2019
基本上,您在主DLL中编写了一个函数,该延迟延迟加载失败时会得到通知。在该函数中,当给定的代码指示失败时,您尝试手动调用LoadLibrary,该路径的路径包括主DLL所在的文件夹以及无法加载的DLL的名称
如何从主DLL中获取主DLL由您决定。有很多方法。
类似这样的东西:
FARPROC WINAPI delayHook(unsigned dliNotify, PDelayLoadInfo pdli)
{
FARPROC fpRet = NULL;
switch (dliNotify)
{
case dliStartProcessing:
break;
case dliNotePreLoadLibrary:
break;
case dliNotePreGetProcAddress:
break;
case dliFailLoadLib:
{
std::string newPath = GetMyModulePath();
newPath += "\\";
newPath += pdli->szDll;
fpRet = reinterpret_cast<FARPROC>(::LoadLibrary(csDir));
}
break;
case dliFailGetProc:
break;
case dliNoteEndProcessing:
break;
default:
break;
}
return fpRet;
}
//
// Set access to our delay load hook.
//
PfnDliHook __pfnDliFailureHook2 = delayHook;