如何在另一个DLL上的DLL上使用`/ DELAYLOAD`

时间:2019-04-03 14:00:18

标签: c++ visual-studio winapi dll

我有两个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?

1 个答案:

答案 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;