在 Windows 中的 Qt 中加载外部 dll
Posted
技术标签:
【中文标题】在 Windows 中的 Qt 中加载外部 dll【英文标题】:Load external dll in Qt in Windows 【发布时间】:2016-01-06 03:47:04 【问题描述】:假设,我有一个包含我的程序的文件夹,还有另一个包含外部库的文件夹。
bin
myprog.exe
etc
lib.dll
sublib.dll
就我而言,我想从我的主程序myprog.exe
加载lib.dll
。问题是lib.dll
与sublib.dll
链接。
所以我尝试这样做:
QCoreApplication a(argc, argv);
QLibrary lib;
QString path = "C:/etc/lib.dll";
a.addLibraryPath(path);
if(QLibrary::isLibrary(path))
lib.setFileName(path);
lib.load();
if(lib.isLoaded())
qDebug() << "Ok\n";
else
qDebug() << "Error " << lib.errorString() << "\n";
else
qDebug() << "Not a library\n";
return a.exec();
运行应用程序后出现错误:
无法加载库 lib.dll 找不到指定的模块
如果我将lib.dll
和sublib.dll
都放在bin
目录中,它可以正常工作。但这不是我想做的。
我试过了
a.addLibraryPath("C:/etc");
但这不起作用。
据我了解QCoreApplication::addLibraryPath()
设置 Qt 程序的路径,而不是系统范围的设置。所以,在这种情况下,lib.dll
仍然找不到 sublib.dll
尽管它位于同一目录中。
所以我的问题 - 我如何在 Qt 程序中加载外部共享库,以防这个库有自己的依赖项?
【问题讨论】:
你确定给定正确 EXE 的 lib.dll 会加载 sublib.dll 吗? 是的,如果我将两个 dll 都放在c:/bin
或 C:/Windows/System32
中,它可以正常工作。
逃离 Windows dll 地狱的唯一安全方法是将 dll 及其依赖项复制到应用程序目录中。磁盘空间很便宜。受苦的肯定方法是将它们转储到 system32 目录中。
【参考方案1】:
那是 Windows 的问题。 DLL 将在当前进程目录中查看,然后在系统 PATH 中查看。某些C:\etc\lib.dll
中包含的代码在其自己的进程中运行,除非实现的非常具体的逻辑将按照系统规则运行。
详情请参考 MSDN 文章Dynamic-Link Library Search Order。如果该 lib.dll 的源代码可用,则检查LoadLibrary 调用是有意义的。如果没有提供具体路径,则:
搜索的第一个目录是包含图片的目录 用于创建调用进程的文件(有关更多信息,请参阅 CreateProcess 函数)。这样做允许私有动态链接 与进程关联的库 (DLL) 文件,无需找到 将进程的安装目录添加到 PATH 环境中 多变的。如果指定了相对路径,则整个相对路径为 附加到 DLL 搜索路径列表中的每个标记。加载模块 从相对路径而不搜索任何其他路径,使用 GetFullPathName 获取非相对路径并调用 LoadLibrary 非相对路径。有关 DLL 搜索顺序的更多信息, 请参阅动态链接库搜索顺序。
【讨论】:
谢谢@AlexanderVX!正如我所见,唯一的方法是将c:/etc
添加到 PATH 变量中,因为这两个 dll 都不是我的,我不知道它们是如何加载的。【参考方案2】:
没有什么可以阻止您显式预加载 lib.dll
所依赖的库。一旦预加载,它们就可以供您随后打开的任何库使用。毕竟,您知道它们在哪里,因此迭代它们并尝试加载它们是一件简单的事情。由于这些库之间可能存在依赖关系,您必须继续加载它们,直到没有更多进展:
QString path;
QSet<QString> libraries;
QDirIterator itpath, "*.dll";
while (it.hasNext())
libraries << it.next();
bool progress = true;
while (progress)
progress = false;
for (auto i = libraries.begin(); i != libraries.end();)
QLibrary lib*i;
if (lib.load())
progress = true;
i = libraries.erase(i);
else
++i;
要么就是这样,要么使用你选择的PE库来自己构建依赖树,并且只打开必要的库,按依赖顺序。
附注:你不拥有C:\Windows
,你不应该在任何现代安装程序中在那里(也不在任何子文件夹中)写任何东西。
【讨论】:
以上是关于在 Windows 中的 Qt 中加载外部 dll的主要内容,如果未能解决你的问题,请参考以下文章