【问题标题】:How do I programmatically find why a DLL fails to load?如何以编程方式查找 DLL 加载失败的原因?
【发布时间】:2016-07-25 08:28:05
【问题描述】:

我的 C++ 程序调用 LoadLibraryEx() 来加载第三方 DLL。结果是一个空句柄 - 它无法加载。之后对GetLastError() 的调用返回零,这并没有多大用处,但至少它不是丢失的 DLL 文件。

代码如下:

 HINSTANCE instance = ::LoadLibraryExW(
     path, 0, LOAD_WITH_ALTERED_SEARCH_PATH );
 if (instance == 0)
 {
     DWORD lastError = GetLastError();
     LOG( "Failed to load, error code is " +
         LastErrorAsString( lastError ));
     return E_FAIL;
 }

我无法访问那台机器 - 我只能在那里部署代码并观察上传到网络存储的日志。

如何以编程方式找出 DLL 加载失败的原因?

【问题讨论】:

  • 您在检查NULL 句柄后是否直接 调用GetLastError?你没有在两者之间调用任何其他函数?
  • 能否请您分享代码而不是引用您正在使用的功能。它将帮助我们尝试为您找出问题。
  • @JonathonOgden 添加了一个 sn-p
  • @JoachimPileborg 是的,这是我检查的第一件事。
  • 来自 MSDN:如果使用此值并且 lpFileName 指定了绝对路径,系统将使用备注部分中讨论的备用文件搜索策略来查找指定模块导致加载的关联可执行模块。如果使用此值并且 lpFileName 指定相对路径,则行为未定义。你确定使用的是绝对路径吗?

标签: c++ winapi visual-c++ dll loadlibrary


【解决方案1】:

可能您的 dll 可以找到,但它依赖于在远程计算机上找不到的 dll。

如果您不能使用 Dependency Walker,那么您可以尝试使用以下文章中描述的技术:

How to determine a windows executables DLL dependencies programatically?

【讨论】:

  • 在这种情况下 GetLastError 必须返回 ERROR_MOD_NOT_FOUND 和/或 RtlGetLastNtStatus - STATUS_DLL_NOT_FOUND - 所以这不解释
  • forums.codeguru.com/… 这不是解释,而是搜索的方向。无论如何,我建议搜索为什么 LoadLibraryExW 返回 null 而 GetLastError 返回 SUCCESS
  • 这绝对不能解释为什么GetLastError返回0
【解决方案2】:

好的,所以我检查得更好——确实有另一个 WinAPI 调用导致“最后一个错误”在LoadLibraryEx() 之后被覆盖。它隐藏在几层 C++ 辅助对象的深处,所以我之前没有注意到它。所以这是调用者代码中的一个错误,真正的“最后一个错误”不是零。

【讨论】:

  • funny ) 你早就说在 LoadLibraryExW 之后调用了 GetLastError()。但是,如果您在测试中尝试了 LdrLoadDll - 只需几分钟即可让所有人理解
  • 更重要的是,如果您发布的是实际代码而不是假代码,我们会立即发现问题。我实际上曾想过要问这个问题,但假设一个 108k-rep 的用户会知道得更好。我猜这会教我。
  • @HarryJohnston 我知道。我无法发布实际代码,因为首先,它是专有代码,其次,它有很多依赖项。我的印象是我发布的代码与真实的代码相同。在这种情况下你会怎么做?
  • 要么 (a) 获得发布代码 sn-p 的权限,要么 (b) 测试我计划发布的代码,以确保它确实重现了问题。至少你可以避免告诉 Joachim 这是“我检查的第一件事”。 :-)
  • @HarryJohnston 老实说,我相信我确保中间没有 WinAPI 调用,但事实证明我错了。
【解决方案3】:

看起来问题很可能是安装了挂钩或其他防病毒措施的第三方软件,挂钩可能有错误并且没有设置正确的最后错误代码。

作为一种故障排除措施,您应该尝试使用 LdrLoadDll 而不是 LoadLibraryEx。

请注意,这是一个未记录的内部函数,因此您可能不希望在生产代码中使用它,但这将是一个有用的故障排除步骤,因为它应该会产生更有用的错误代码。

【讨论】:

  • 在发布建议使用未记录的内部函数的答案时,您应该明确说明这一点。虽然了解内部结构有助于诊断问题,但基于这些实现细节的解决方案通常无济于事,应标记为“不支持”“可能随时中断”
  • “LdrLoadDll [...] 是最好的 [...] 选择” - 这取决于您的要求。如果您实现了一个有趣的项目,并且不在乎,如果未来的 Windows 更新破坏了它,那么请继续使用它。如果您编写一些关键任务代码,您肯定想使用不受支持的系统调用。做出该决定不是您的责任。但是,您有责任记录所提议的解决方案不受支持,以便读者可以根据这一重要细节做出决定。
  • 这没有提供问题的答案。要批评或要求作者澄清,请在他们的帖子下方留下评论。 - From Review
  • @Wernsey 的问题是“为什么 DLL 无法加载?”。如果 LdrLoadDll 返回状态!= 0 (
  • 是的,我明白你在说什么,尽管可能只是因为你对 IInspectable 的第一条评论的回复,而且你会注意到我向 OP 发表了一条评论,支持你的建议。二十年前,我可能已经发布了与此类似的答案。我现在知道而我当时不知道的是,仅仅写下你的意思是不够的,你必须考虑读者如何解释它。在这种情况下,典型的读者是不会理解上下文的,它会被解释为“如果 LoadLibrary 不起作用,试试 LdrLoadDll,它会更好”。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-10-01
  • 2014-05-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-29
相关资源
最近更新 更多