动易 网站首页,创意网页设计素材模板,小程序模板商城,拼多多开网店怎么开 新手文章目录 1. 创建共享库2. 使用共享库2.1 共享库的调用方式2.2 隐式链接调用共享库2.3 显式链接调用共享库 1. 创建共享库
除了静态库#xff0c;Qt 还可以创建共享库#xff0c;也就是 Windows 平台上的动态链接库。动态链接库项目编译后生成 DLL 文件#xff0c;DLL 文件… 文章目录 1. 创建共享库2. 使用共享库2.1 共享库的调用方式2.2 隐式链接调用共享库2.3 显式链接调用共享库 1. 创建共享库
除了静态库Qt 还可以创建共享库也就是 Windows 平台上的动态链接库。动态链接库项目编译后生成 DLL 文件DLL 文件在 windows 平台上应用广泛。DLL 文件是在应用程序运行时加载的不像静态库那样在编译期间就连编到应用程序里。若更新了 DLL 文件版本只要接口未变应用程序依然可以调用。
创建共享库项目单击Qt Creator 的“File”-“New File or Project”菜单项在 New File orProject 对话框中选择 Projects 组里的 Library在右侧的具体类别中再选择 C Library单击“Choose*·.”按钮后出现如下图 所示的向导对话框。 在此对话框的 Type 下拉列表框里选择 Shared Library并给项目命名例如 mySharedLib再选择项目保存目录。单击“Next”按钮后选择编译器下一步选择需要包含的 Qt 模块再下一步是类定义页面在其中输入类的名称这里仍然输入类名称为QWDialogPen再下一步结束即可。
由向导生成的 mySharedLib项目包含文件 mySharedLib.pro、qwdialogpen.h 和qwdialogpen.cpp。此外还有一个特殊的头文件 mysharedlib global.h。结构如下图所示 mysharedlib global.h文件的内容如下:
#ifndef MYSHAREDLIB_GLOBAL_H
#define MYSHAREDLIB_GLOBAL_H#include QtCore/qglobal.h#if defined(MYSHAREDLIB_LIBRARY)
# define MYSHAREDLIBSHARED_EXPORT Q_DECL_EXPORT
#else
# define MYSHAREDLIBSHARED_EXPORT Q_DECL_IMPORT
#endif#endif // MYSHAREDLIB_GLOBAL_H这里定义了符号MYSHAREDLIBSHARED_EXPORT用于替代Qt的宏Q_DECL_EXPORT或Q_DECL_IMPORT。
一个共享库导出给用户使用的类、符号、函数等都需要用宏Q_DECL_EXPORT来定义导出一个使用共享库的应用程序需要通过Q_DECL_IMPORT导入共享库里的可用对象。
在mySharedLib.pro文件中增加了符号MYSHAREDLIB_LIBRARY的定义下面是mySharedLib.pro文件的主要内容
QT widgetsTARGET mySharedLib
TEMPLATE libDEFINES MYSHAREDLIB_LIBRARY
DEFINES QT_DEPRECATED_WARNINGS自动生成的 qwdialogpen.h 文件里的内容是对 QWDialogPen 类的定义在类名称前使用了宏MYSHAREDLIBSHARED_EXPORT定义QWDialogPen 为一个导出的类。
#ifndef QWDIALOGPEN_H
#define QWDIALOGPEN_H#include QDialog
#include QPen
#include mysharedlib_global.hnamespace Ui {
class QWDialogPen;
}class MYSHAREDLIBSHARED_EXPORT QWDialogPen : public QDialog
{ //QPen属性设置对话框Q_OBJECT
private:QPen m_pen; //成员变量
public:explicit QWDialogPen(QWidget *parent 0);~QWDialogPen();void setPen(QPen pen); //设置QPen用于对话框的界面显示QPen getPen(); //获取对话框设置的QPen的属性static QPen getPen(QPen iniPen, bool ok); //静态函数private slots:void on_btnColor_clicked();
private:Ui::QWDialogPen *ui;
};#endif // QWDIALOGPEN_H
将 12.3 节静态库项目里的文件 qwdialogpen.h、qwdialogpen.cpp 和 qwdialogpen.ui 复制到本项目目录下覆盖自动生成的初始文件但是修改文件 qwdialogpen.h 里的类的定义在类名称前增加MYSHAREDLIBSHARED_EXPORT 宏并加入mysharedlib global.h 的包含语句。
项目的文件准备好之后就可以编译生成 DLL 文件根据使用的编译器不同生成的文件有些区别。
若使用 MSVC 编译编译后会生成 mySharedLib.dll 和 mySharedLib.lib 两个文件mySharedLib.dll 在运行应用程序时调用mySharedLib.lib 在应用程序隐式调用动态链接库时使用。若使用 MinGW 编译编译后会生成 mySharedLib.dll 和 libmySharedLib.a 两个文件mySharedLib.dll 在运行应用程序时调用libmySharedLib.a 在应用程序隐式调用动态链接库时使用。
采用 debug 和release 不同模式生成的文件只能当应用程序在 debug 或release 模式下编译或调用。
由于动态库的代码和上篇静态库的基本一样只是多了mysharedlib global.h文件这里就不再赘述了。
2. 使用共享库
2.1 共享库的调用方式
调用动态链接库有两种形式隐式链接 (implicit linking)调用和显式链接 (explicit linking)调用。 隐式链接调用是在编译应用程序时有动态库的 lib 文件(或a 文件)和 h 头文件知道 DLL中有哪些接口类和函数编译时就隐式地生成必要的链接信息使用 DLL 中的类或函数时根据h头文件中的定义使用即可。应用程序运行时将自动加载 DLL 文件。隐式链接调用主要用于同一种编程软件(如 Qt)生成的代码的共享。 显式链接调用是只有 DLL 文件知道 DLL 里的函数原型使用 QLibrary 类对象在应用程序里动态加载 DLL 文件声明函数原型并使用 DLL 里的函数。这种方式需要在应用程序里声明函数原型并解析 DLL 里的函数。
2.2 隐式链接调用共享库
创建一个基于QMainWindow 的应用程序 shareLibUser程序功能与 12.3 节的 LibUser 项目一样将LibUser 项目的 mainwindow 相关3 个文件mainwindow.h、mainwindow.cpp 和mainwindow.ui复制到 shareLibUser 项目下替换自动生成的文件。
在 shareLibUser 项目文件目录下新建一个 include 目录将 mySharedLib 项目的两个头文件qwdialogpen.h 和 mysharedlib_global.h 复制到此目录下。若使用 MSVC 编译器则将 release 版本的mySharedLib.lib 复制到此目录下debug 版本的 mySharedLib.lib 更名为 mySharedLibd.lib 复制到此目录下;若使用 MinGW 编译器则复制 release 版本的 libmySharedLib.adebug 版本的libmySharedLib.a 更名为 libmySharedLibd.a 复制到此目录下。
为应用程序增加动态链接库右键单击 shareLibUser 项目节点在快捷菜单里单击“Add Library···”菜单项在出现的向导对话框里首先选择添加的库类型为“Extermal Library”在向导第二步设置导入的动态库文件(见下图)。 在上图中选择项目 include 目录下的 mySharedLib.lib 文件或libmySharedLib.a 作为库文其他设置如上图所示。
完成后在shareLibUser.pro 文件中自动增加项目设置的语句如下:(目的也是为了下面的程序也可以不通过UI操作自己写相应的代码)
win32:CONFIG(release, debug|release): LIBS -L$$PWD/include/ -lmySharedLib
else:win32:CONFIG(debug, debug|release): LIBS -L$$PWD/include/ -lmySharedLibdINCLUDEPATH $$PWD/include
DEPENDPATH $$PWD/include项目编译时会根据当前是 release 还是 debug 模式自动添加相应的库文件。这里添加库文件只是使用了动态库的导出定义而不是将库的实现代码连接到应用程序的可执行文件里。主窗体类 MainWindow 的功能与上篇静态库 的程序完全一致调用共享库里的类OWDialogPen也无需特别说明只需包含头文件 qwdialogpen.h 即可。
注意必须将动态链接库文件 mySharedLib.dll复制到可执行文件的目录下程序才可以正常运行mySharedLib.dll 的 debug 和 release 版本必须分别用于应用程序的 debug 和 relcase 版本否则运行时出错。
使用动态链接库可以很方便地扩展应用程序的功能但是 DLL 文件需要随应用程序一起发布并且编译 DLL和应用程序的 Qt 版本最好保持一致否则需要考虑二进制兼容问题。关于二进制兼容可以参考Qt源代码中二进制兼容及d、q指针的理解
2.3 显式链接调用共享库
显式链接调用共享库是在应用程序运行时才加载共享库文件并调用库里的函数的。应用程序编译时无需共享库的任何文件只需知道函数名和函数的原型即可。所以这种方式可以调用其他语言编写的 DLL 文件例如用 Delphi 生成的一个DLL 文件。
显式链接调用共享库是通过 QLibrary 类实现的。QLibrary 是与平台无关的用于在运行时载入共享库一个 QLibrary 对象只对一个共享库进行操作。
一般在 QLibrary 的构造函数中传递一个文件名可以是带路径的绝对文件名也可以是不带后缀的单独文件名。QLibrary 会根据运行的平台自动查找不同后缀的共享库文件例如 Unix 上是.so”Mac上是“.dylib”Windows 上是“.dll”。
作为示例用 Delphi编写一个 DLL 项目生成一个 DelphiDLL.dll文件这个文件里只有一个函数函数的原型为:
function triple(N;integer):integer;它会计算传递参数N的3倍值并返回。
在Qt Creator 里创建一个基于 QMainWindow 的应用程序DelphiDLLUser设计一个简单的界面运行时下图所示。单击按钮时将根据输入调用动态链接库 DelphiDLL.d11里的triple()函数计算结果并显示在输出编辑框里。
按钮的槽函数代码如下
void MainWindow::on_pushButton_clicked()
{QLibrary myLib(DelphiDLL);if (myLib.isLoaded())QMessageBox::information(this,信息,DelphiDLL.DLL已经被载入,第1处);typedef int (*FunDef)(int); //函数原定定义FunDef myTriple (FunDef) myLib.resolve(triple); //解析DLL中的函数int VmyTriple(ui-spinInput-value()); //调用函数ui-spinOutput-setValue(V);if (myLib.isLoaded())QMessageBox::information(this,信息,DelphiDLL.DLL已经被载入,第2处);
}在定义QLibrary对象实例 myLib 时传递了共享库文件名“DelphiDLL”这里不需要给出后缀名。DelphiDLL.dll 文件必须在应用程序同一目录、系统目录或可搜索目录下。
QLibrary 有几个函数用于 DLL文件的载入与卸载 load()用于手动载入 DLL 文件到内存里一般无需手工调用此函数在DLL里的函数第一次被使用时 QLibrary 会自动调用此函数 isLoaded()用于判断 DLL是否已经被载入内存 unload()用于将DLL从内存中卸载。
一个动态链接库在内存里只能有一个实例也就是即使有多处调用了这个动态链接库里的函数它也只会被载入一次如果不是所有的实例都使用 unload()卸载它那么它会在应用程序退出时才卸载。
在槽函数on_pushButton_clicked()的代码里有两处QMessageBox 显示信息。在运行应用程序第一次单击按钮时只有第 2 处信息框显示说明声明了 QLibrary 对象后动态链接库没有立即被载入内存第二次单击按钮时两处信息框会先后显示说明动态链接库上次载入内存后还在内存里。
显式调用动态链接库里的函数需要声明函数原型的类型即:
typedef int (*FunDef)(int); //函数原定定义然后使用QLibrary的resolve()函数解析需要调用的函数。
FunDef myTriple (FunDef) myLib.resolve(triple); //解析DLL中的函数
这样就定义了一个函数 myTriple用于实现 DLL文件里的函数triple的功能当然重新声明的函数名称可以和 DLL 里的函数名称完全相同。
如果 DelphiDLL.dll 文件没有复制到应用程序目录下则编译和启动应用程序都不会出错只有单击按钮调用 DLL 里的函数时才会出错。所以要使应用程序正常运行需要将 DelphiDLL.dIl文件复制到应用程序目录下。(实际操作时发现即使复制进去点击后会显示“程序异常结束”后期实践时再测试)