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

问题描述 投票:0回答:1

我有两个DLL的解决方案。第一个是“主”DLL。它碰巧是一个ODBC驱动程序,但我认为这对于这个问题并不重要。第二个DLL包含第一个DLL的所有UI逻辑。由于并不总是需要UI,我想使用明确说明的/DELAYLOAD功能:

可以在构建.EXE或.DLL项目期间指定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?

c++ visual-studio winapi dll
1个回答
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;
© www.soinside.com 2019 - 2024. All rights reserved.