我可以单独获取DLL来解析导入的DLL吗?

时间:2016-08-01 11:58:04

标签: c++ windows winapi dll

我有一些像这样排列的DLL:

  • lib.dll - 第三方DLL,其中包含您链接到
  • 的导入库
  • plugin.dll - 一个链接到lib.dll的DLL,一个旨在通过LoadLibrary加载到主机程序中的插件
  • other\plugin.dll - 另一个链接到lib.dll
  • 的插件DLL
  • other\lib.dll - otherplugin的lib.dll
  • 副本

(这些只是普通的DLL,带有一些导出的函数 - 我没有使用COM或其他东西。)

在我的测试设置中,如果我使用LoadLibrary加载plugin.dll,然后使用LoadLibrary加载other\plugin.dll,则它们似乎都共享相同的加载副本lib.dll。但实际上我需要other\plugin.dll来加载other\lib.dll - 我不希望共享库。

我可以这样做吗? (理想情况下无需重新编译lib.dll。)

2 个答案:

答案 0 :(得分:3)

允许此操作的技术称为应用程序隔离。它的工作方式是让开发人员使用清单文件将他们的dll安排到Side by Side程序集中。

在MSDN上阅读Isolated Applications以获取官方文档。

或者,这可以在没有这一切的情况下工作,假设你实际上正在加载" lib.dll"明确地通过LoadLibrary

首先,请注意,当Dll调用LoadLibrary时,不会搜索DLL自己的文件夹。如果您在MSDN上查看LoadLibrary的文档,您将看到应用程序可执行文件夹是首选搜索位置。因此,您需要做的第一件事是在加载Plugin.dll之前调用SetDllDirectory,以便它实际上可以找到自己的" lib.dll"。

下一步 - 请注意,LoadLibrary搜索路径仅在传递相对路径时使用。

所以,如果你首先修复DllDirectory和LoadLibrary" Plugin.dll"然后调用LoadLibrary,将完全限定的路径传递给您自己的Lib.dll副本,然后plugin.dll将使用搜索路径加载自己的版本,您的应用将显式加载自己的版本。

答案 1 :(得分:1)

还有另一种选择:将DLL设置为延迟加载,并使用the delay load DLL import hook显式加载所需的DLL。

当解决延迟加载的DLL时,通常系统(虽然我不确定哪个部分 - 可能是CRT?)会发现已经加载了plugin.dll并分发了另一个句柄它。但是使用延迟加载DLL挂钩,您可以使用LoadLibrary加载另一个DLL - 在这种情况下是共享DLL的插件特定副本。提供完整路径,因此LoadLibrary无法返回现有DLL的句柄。

为此,请将DLL的HINSTANCE存储在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做同样的事情......)