1

我在 Windows 上遇到了 LoadLibrary 的一个奇怪问题。首先是一些背景。此应用程序依赖于 Qt,并且 Qt 被拆分为多个库。我正在尝试升级 Qt 的版本,但不会破坏任何人。较新的 Qt 库向后兼容旧的库。这意味着使用旧版本构建的应用程序可以在加载新版本时运行。反之则不然——如果加载了旧版本,使用新版本构建的应用程序将缺少符号。

Qt DLL 位于特定于版本的目录中(例如c:\qt\qt-4.5.2\libc:\qt\qt-4.8.1\lib作为示例)。大多数开发人员在他们的 PATH 中还有一个公共目录,其中包含我们使用的所有第三方库的“当前”版本(称为它c:\common\lib)。这是运行应用程序时通常可以找到 Qt 库的地方。

我将新的 Qt 版本库放在公共位置,一切似乎都工作正常,除了一种情况。有问题的应用程序被拆分为多个库,其中一些是通过调用加载的LoadLibrary()。其中一些运行时加载的 DLL 依赖于 Qt 库。在一种情况下,加载的 DLL 依赖于QtXml,而后者本身又依赖于QtCore.

这就是它变得奇怪的地方。应用程序依赖QtCore并加载依赖于QtXml. 应用程序和库是与旧版本的 Qt 链接构建的。如果此应用程序仅使用 PATH 中的公共目录运行,则一切正常,因为新的 Qt 版本 DLL 是从公共目录加载的。但是,如果 PATH 包含在公共目录之前存储旧 Qt 版本 DLL的目录,则加载运行时 DLL 会失败并丢失符号。

(在进行自动化单元测试时会出现这种情况,脚本显式设置 PATH 以使用特定的库版本。)

据我所知,应用程序正在加载旧版本,QtCore.dll运行时加载的 DLL 正在(不知何故)加载新版本QtXml.dll,因为已经加载QtCore的没有它需要的符号,所以失败了。

但这似乎是不可能的,因为 PATH 类似于c:\qt\qt-4.5.2\lib;c:\common\lib(加上其他不相关的路径)。如果我从公共 lib 目录中删除较新QtXml的(不是用旧版本替换,只是删除它),然后LoadLibrary()成功,因为它加载了所有 Qt 库的 4.5.2 版本。但这不是一个好的长期解决方案,因为在 PATH(常见)中没有 Qt 特定版本目录的情况下运行将无法找到QtXml.

这怎么可能?如何LoadLibrary()(或任何它递归调用以解决库的依赖项)从后面PATH? 我找不到任何表明公共库目录被特别考虑的东西(它不是一个设置的 DLL 目录)。在构建过程中没有提到它,它只是开发人员PATH为了方便而拥有的东西。

顺便说一句,在 Linux 上存在类似的情况LD_LIBRARY_PATHand dlopen(),它在那里工作得很好。这是 Windows 正在做的不同的事情,我不明白。有没有人知道可能出了什么问题?

4

1 回答 1

3

LoadLibrary has lots of surprising behaviors. Make sure you fully grok all of the Remarks for it in MSDN.

If there's already a library loaded (any version) with the same name, LoadLibrary just returns a handle to the already-loaded DLL. That may be coming into play in your scenario.

Next, if you've specified a relative path or just a file name, LoadLibrary applies arcane search rules. Your PATH variable is typically the last place to search. It's likely that some other rule is finding the "wrong" DLL before it even gets to checking the PATH. A good guideline is to always use an absolute path the file you want to load to be sure that its search rules don't grab the wrong file. A common security flaw is to not control where LoadLibrary searches, and an attacker convinces your application to load a doctored DLL.

And, finally, it's possible for an installer to apply DLL redirection that can override what you ask for and where it might be found. I'm not sure if this is common for Qt DLLs or not, but you might want to check your registry.

I've occasionally used ProcMon from SysInternals to observe a program while it's loading DLLs. You can see each place it checks, which may give you a clue as to why it's finding the wrong version.

于 2012-06-19T13:16:45.453 回答