【问题标题】:LoadLibrary does not reuse loaded libraryLoadLibrary 不重用加载的库
【发布时间】:2014-02-16 15:11:55
【问题描述】:

我的目录结构如下:

test
  dir
    a.dll  <-- version 1
  a.dll    <-- version 2
  myapp.exe

我希望LoadLibrary("dir\\a.dll") 单独使用版本 1,LoadLibrary("a.dll") 将使用版本 2,同时一起使用:

LoadLibrary("dir\\a.dll");
LoadLibrary("a.dll");

根据the documentation of LoadLibrary,两者都将引用版本 1。

但是,当我尝试在我正在处理的应用程序中执行此操作时,第 1 行加载第 1 版,第 2 行加载第 2 版。

我尝试编写一个小型复制器,但在复制器中它按预期工作 - 所以在较大的应用程序或加载的 dll 中有些东西会破坏它。 是什么原因造成的,我该如何解决?

需要强调的是,这两个负载在较大的应用程序中是相邻的,在第 1 行和第 2 行之间没有系统调用(当然是同一个过程)。我本来是想在它们之间放很多代码,但是看到这个问题,即使它们相邻也重现了。

我也尝试过以下目录结构:

test
  dir
    a.dll  <-- version 1
  myapp.exe
Windows
  System32
    a.dll  <-- version 2

但同样,第 1 行加载第 1 版,第 2 行加载第 2 版。

【问题讨论】:

  • 解释你是如何知道 DLL 被再次加载的。并且不要混淆最重要的信息,即文件名。
  • @HansPassant 我在返回的句柄上使用GetModuleFileName 来验证加载的dll 的实际路径。此外,当从 dll 运行函数时,我看到它根据其行为来自版本 2。你说的文件名是什么意思? dll的名字有意义吗?我认为这里唯一重要的是同名吗?
  • @HansPassant here's a link to the complete reproducer code(按预期工作)。大型应用程序中的代码几乎相同,只是从方法内部而不是从main 运行。它是 C++ 而不是 C,但据我了解,它不应该有所作为。
  • GetModuleFileName 不会告诉您一个 DLL 被加载了两次。调试器的模块列表可以。
  • “完整的复制代码(按预期工作)”是什么意思?它会重现问题,还是按预期工作?

标签: c windows dll loadlibrary


【解决方案1】:

我设法找到了解决方案。事实上,它只需要一些思考 - 回想起来答案是显而易见的:当我第一次调用LoadLibrary 之前已经加载了 dll 时,可能会发生这种情况。因此,第一次调用,带有显式路径,加载版本 1 - 而第二次调用,没有路径,默认为 first 加载的 dll(根据文档),恰好是版本 2。

这可以通过在第一次 LoadLibrary 调用之前强制卸载库来解决:

HMODULE alreadyLoaded = GetModuleHandle("a.dll");
if (alreadyLoaded) {
    FreeLibrary(alreadyLoaded);
}

虽然这对我来说已经足够了,但更完整的解决方案是循环执行,以处理之前多次加载 dll 的情况:

HMODULE alreadyLoaded = GetModuleHandle("a.dll");
while (alreadyLoaded) {
    FreeLibrary(alreadyLoaded);
    alreadyLoaded = GetModuleHandle("a.dll");
}

当然,这是有潜在危险的 - 特别是如果原始的 HMODULE 存储在某个地方,因为这会使其无效。

【讨论】:

  • 这可能会破坏首先加载库的任何代码。
  • ... 相反,请考虑在两个调用中使用显式路径,例如 LoadLibrary(".\\a.dll")
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多