使用 P/Invoke 调用 dll 时,为啥 LoadLibrary 在某些机器上会失败?

Posted

技术标签:

【中文标题】使用 P/Invoke 调用 dll 时,为啥 LoadLibrary 在某些机器上会失败?【英文标题】:Why is LoadLibrary failing in some machines when calling a dll using P/Invoke?使用 P/Invoke 调用 dll 时,为什么 LoadLibrary 在某些机器上会失败? 【发布时间】:2018-11-02 20:37:57 【问题描述】:

我有一个使用 P/Invoke 调用 C++ API 的 .NET 应用程序。 C++ dll 依赖于第三方 dll。该第三方 dll 调用 LoadLibrary 来动态加载 libeay32.dll,这是一个 OpenSSL 依赖项。

经过多次测试,我发现 .NET 应用程序在 Windows 10 中可以正常工作,但在使用 Windows 7 的某些部署中失败。失败的原因是因为 .NET 进程没有加载 libeay32.dll。我尝试将 libeay32.dll 放在与进程相同的目录和系统文件夹中(记住动态加载搜索顺序),但故障仅在 Windows 7 32 位中持续存在。此外,如果我从 C++ 控制台应用程序调用 API dll,它在所有平台上都没有问题。为了解决我在 .NET 应用程序中调用 LoadLibrary 的问题,在对 C++ API 进行 P/Invoke 调用之前,它适用于所有目标平台(Windows 10/7 32 位和 64 位)。

如果从使用 P/Invoke 调用的 API 的 C++ dll 依赖项调用,为什么 LoadLibrary 在 Windows 7 中加载 libeay32.dll 而在 Windows 10 中加载失败?

编辑 cmets的一些笔记:

    所有编译的程序集都针对 x86 架构。 在发布问题之前,我确认没有依赖文件 缺少的地方,使用依赖walker。

【问题讨论】:

那么,LoadLibrary失败时返回的错误码是什么? 无法获取错误代码,因为 LoadLibrary 是在第三方 dll 中调用的,我无权访问源代码。 好吧,这使这成为一个不成问题的问题。你问的是我们看不到的代码。 从.Net应用加载dll而不是依赖加载时,搜索路径是否可能不同? 如果您对设置快速 DLL 测试项目感到满意,我首先确定我可以在目标平台上的本机 C++ 上下文中加载该死的东西,既可以通过 import lib 隐式加载,也可以通过显式加载加载库。靠近金属,然后重新添加托管/本机过渡内容。您还可以在紧要关头使用 Detours 拦截对 LoadLibrary 的调用,获取内部错误代码,实际上您可能甚至不需要走那么远,调试器可以限制这个 【参考方案1】:

可能是因为 dll 依赖于一些丢失的文件。使用dependency walker 并查看它需要哪些文件。检查两个系统。该工具将以红色显示丢失的文件。不要盲目复制文件。看看它们是什么,部署它们需要什么运行时或设置,并正确部署它们。

【讨论】:

其实这可能是更实用的建议 我使用了依赖遍历器,并且在依赖链中的任何 dll 发生故障的任何平台中都没有丢失任何文件。 然后按照Debugging LoadLibrary Failures的步骤,找出原因。【参考方案2】:

.Net 应用程序可以使用 AnyCPU 作为目标构建,并在 64 位和 32 位模式下运行,但是如果您为目标选择 AnyCPU,操作系统将根据自己的偏好选择一个。如果您具有本机依赖项,​​这可能意味着您所依赖的库无法加载,因为您运行的位数错误。如果您可以将应用程序限制为您期望的位数,它可能会更好地工作。

【讨论】:

感谢您的建议。奇怪的是,在测试期间所有程序集都针对 x86,唯一失败的平台是 32 位 Windows 7。 您之前是否尝试过使用 sysinternals 进程监视器?它会告诉您应用程序何时尝试打开文件和搜索顺序。可能是您的操作系统没有找到正确的位置,或者文件未注册 我以前用过但忘记了。感谢您的提醒。会试试的。

以上是关于使用 P/Invoke 调用 dll 时,为啥 LoadLibrary 在某些机器上会失败?的主要内容,如果未能解决你的问题,请参考以下文章

P/Invoke 是不是执行 DLL 然后将其关闭?

如何 p/invoke 调用函数仅使用但 C++ 需要 .a/.lib/.o 文件?

为啥 Cdecl 调用在“标准”P/Invoke 约定中经常不匹配?

为啥 Cdecl 调用在“标准”P/Invoke 约定中经常不匹配?

P/Invoke 动态 DLL 搜索路径

C#高阶与初心:P/Invoke平台调用