Qt 调用动态库 插件

来源:互联网 发布:全国软件开发人员 编辑:程序博客网 时间:2024/06/05 07:54

文章来源:http://blog.csdn.net/tujiaw/article/details/37989519


1.隐式调用

1>新建一个C++库,工程名为Cal,自动生成三个文件cal.h, cal_global.h, cal.cpp,编译后生成我们需要的Cal.lib, Cal.dll

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. #ifndef CAL_H  
  2. #define CAL_H  
  3.   
  4. #include "cal_global.h"  
  5.   
  6. class CALSHARED_EXPORT Cal  
  7. {  
  8.   
  9. public:  
  10.     Cal();  
  11.     int add(int a, int b);  
  12.     int substract(int a, int b);  
  13. };  
  14.   
  15. #endif // CAL_H  

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. #include "cal.h"  
  2.   
  3.   
  4. Cal::Cal()  
  5. {  
  6. }  
  7.   
  8. int Cal::add(int a, int b)  
  9. {  
  10.     return a + b;  
  11. }  
  12.   
  13. int Cal::substract(int a, int b)  
  14. {  
  15.     return a - b;  
  16. }  
2>新建一个Qt应用程序,工程名为CalTest

在CalTest.pro文件所在目录下新建一个lib->cal目录,将cal相关文件拷贝到这个目录下:cal.h, cal_global.h, Cal.lib;

在CalTest.pro文件后面增加两行代码:

INCLUDEPATH += $${PWD}/lib/cal
LIBS += $${PWD}/lib/cal/Cal.lib

我们在构造函数里面测试,代码如下:

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. #include "dialog.h"  
  2. #include "ui_dialog.h"  
  3. #include "cal.h"  
  4. #include <QDebug>  
  5.   
  6. Dialog::Dialog(QWidget *parent) :  
  7.     QDialog(parent),  
  8.     ui(new Ui::Dialog)  
  9. {  
  10.     ui->setupUi(this);  
  11.     Cal cal;  
  12.     int a = 100, b = 200;  
  13.     int addResult = cal.add(a, b);  
  14.     int substractResult = cal.substract(a, b);  
  15.     qDebug() << "add:" << addResult << ",substract:" << substractResult;  
  16. }  
  17.   
  18. Dialog::~Dialog()  
  19. {  
  20.     delete ui;  
  21. }  

编译完成之后,将Cal.dll文件拷贝到生成的CalTest.exe目录下运行即可。

隐式调用用起来比较方便,但是不太灵活,如果缺少头文件,库文件那么这个程序就编译,执行不了了。


2.显示调用

Cal工程代码如下:

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. #ifndef CAL_H  
  2. #define CAL_H  
  3.   
  4. #include "cal_global.h"  
  5.   
  6. class CALSHARED_EXPORT Cal  
  7. {  
  8.   
  9. public:  
  10.     Cal();  
  11.     int add(int a, int b);  
  12.     int substract(int a, int b);  
  13. };  
  14.   
  15. extern "C" CALSHARED_EXPORT Cal* createCal();  
  16. extern "C" CALSHARED_EXPORT void deleteCal(Cal *cal);  
  17.   
  18. #endif // CAL_H  
[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. #include "cal.h"  
  2.   
  3.   
  4. Cal::Cal()  
  5. {  
  6. }  
  7.   
  8. int Cal::add(int a, int b)  
  9. {  
  10.     return a + b;  
  11. }  
  12.   
  13. int Cal::substract(int a, int b)  
  14. {  
  15.     return a - b;  
  16. }  
  17.   
  18. Cal* createCal()  
  19. {  
  20.     return new Cal();  
  21. }  
  22.   
  23. void deleteCal(Cal *cal)  
  24. {  
  25.     delete cal;  
  26.     cal = NULL;  
  27. }  

CalTest调用的时候,CalTest.pro里就不需要

INCLUDEPATH += $${PWD}/lib/cal
LIBS += $${PWD}/lib/cal/Cal.lib

这两行代码了,直接看cpp文件

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. #include "dialog.h"  
  2. #include "ui_dialog.h"  
  3. #include <QDebug>  
  4. #include <QLibrary>  
  5. #include "../Cal/cal.h"  
  6.   
  7.   
  8. Dialog::Dialog(QWidget *parent) :  
  9.     QDialog(parent),  
  10.     ui(new Ui::Dialog)  
  11. {  
  12.     ui->setupUi(this);  
  13.   
  14.     typedef Cal* (*CreateCal)();  
  15.     typedef void (*DeleteCal)(Cal *cal);  
  16.   
  17.     QLibrary lib("Cal.dll");  
  18.     if (lib.load()) {  
  19.         CreateCal createCal = (CreateCal)lib.resolve("createCal");  
  20.         DeleteCal deleteCal = (DeleteCal)lib.resolve("deleteCal");  
  21.         if (createCal && deleteCal) {  
  22.             Cal *pcal = createCal();  
  23.             int a = 100, b = 200;  
  24.             int addResult = pcal->add(a, b);  
  25.             int substractResult = pcal->substract(a, b);  
  26.             qDebug() << "add:" << addResult << ",substract:" << substractResult;  
  27.             deleteCal(pcal);  
  28.         } else {  
  29.             qDebug() << "resolve failed";  
  30.         }  
  31.         lib.unload();  
  32.     } else {  
  33.         qDebug() << "load failed";  
  34.     }  
  35. }  
  36.   
  37. Dialog::~Dialog()  
  38. {  
  39.     delete ui;  
  40. }  

#include "../Cal/cal.h"头文件还是需要的,因为我们不知道Cal类是怎么声明的。

这样当这个dll不存在的时候我们的程序还是可以通过编译运行的。

但是这里还存在问题,Cal类我们还是导出了,因为我们演示的是一个比较简单的类,如果这个类比较复杂那么导出就有麻烦了,因为导出类的父类和子类也要导出,所以我们希望这个类不导出也可以使用。

3.纯虚基类,不导出类,通过虚表来定位具体的函数

Cal工程代码

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. #ifndef CALINTERFACE_H  
  2. #define CALINTERFACE_H  
  3.   
  4. #include "cal_global.h"  
  5.   
  6. class CalInterface  
  7. {  
  8. public:  
  9.     virtual ~CalInterface() {}  
  10.     virtual int add(int a, int b) = 0;  
  11.     virtual int substract(int a, int b) = 0;  
  12. };  
  13.   
  14. extern "C" CALSHARED_EXPORT CalInterface* createCal();  
  15. extern "C" CALSHARED_EXPORT void deleteCal(CalInterface *cal);  
  16.   
  17. #endif // CALINTERFACE_H  

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. #include "CalInterface.h"  
  2. #include "cal.h"  
  3.   
  4. CalInterface* createCal()  
  5. {  
  6.     return new Cal();  
  7. }  
  8.   
  9. void deleteCal(CalInterface *cal)  
  10. {  
  11.     delete cal;  
  12.     cal = NULL;  
  13. }  

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. #ifndef CAL_H  
  2. #define CAL_H  
  3.   
  4. #include "cal_global.h"  
  5. #include "CalInterface.h"  
  6.   
  7. class Cal : public CalInterface  
  8. {  
  9.   
  10. public:  
  11.     Cal();  
  12.     virtual ~Cal();  
  13.   
  14.     virtual int add(int a, int b);  
  15.     virtual int substract(int a, int b);  
  16. };  
  17.   
  18. #endif // CAL_H  
Cal.cpp内容和上面一样
CalTest工程调用:

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. #include "dialog.h"  
  2. #include "ui_dialog.h"  
  3. #include <QDebug>  
  4. #include <QLibrary>  
  5. #include "../Cal/CalInterface.h"  
  6.   
  7.   
  8. Dialog::Dialog(QWidget *parent) :  
  9.     QDialog(parent),  
  10.     ui(new Ui::Dialog)  
  11. {  
  12.     ui->setupUi(this);  
  13.   
  14.     typedef CalInterface* (*CreateCal)();  
  15.     typedef void (*DeleteCal)(CalInterface *cal);  
  16.   
  17.     QLibrary lib("Cal.dll");  
  18.     if (lib.load()) {  
  19.         CreateCal createCal = (CreateCal)lib.resolve("createCal");  
  20.         DeleteCal deleteCal = (DeleteCal)lib.resolve("deleteCal");  
  21.         if (createCal && deleteCal) {  
  22.             CalInterface *pcal = createCal();  
  23.             int a = 100, b = 200;  
  24.             int addResult = pcal->add(a, b);  
  25.             int substractResult = pcal->substract(a, b);  
  26.             qDebug() << "add:" << addResult << ",substract:" << substractResult;  
  27.             deleteCal(pcal);  
  28.         } else {  
  29.             qDebug() << "resolve failed";  
  30.         }  
  31.         lib.unload();  
  32.     } else {  
  33.         qDebug() << "load failed";  
  34.     }  
  35. }  
  36.   
  37. Dialog::~Dialog()  
  38. {  
  39.     delete ui;  
  40. }  

这样Cal类就不必要导出了,而且CalInterface.h头文件是比较独立的,不依赖于其他的一些东西。

C++调用方法跟这类似,只是将QLibrary换成了LoadLibrary,GetProcAddress。

4.插件编写(lower-level api)

1>创建C++库,类型选择Qt Plugin,名称CalPlugin,删掉自动生成的genericplugin.h和genericplugin.cpp两个文件

2>创建接口类头文件calinterface.h

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. #ifndef CALINTERFACE_H  
  2. #define CALINTERFACE_H  
  3.   
  4. #include <QtPlugin>  
  5.   
  6. class CalInterface  
  7. {  
  8. public:  
  9.     virtual ~CalInterface() {}  
  10.     virtual int add(int a, int b) = 0;  
  11.     virtual int substract(int a, int b) = 0;  
  12. };  
  13.   
  14. Q_DECLARE_INTERFACE(CalInterface, "org.qt-project.Qt.Examples.CalPlugin.CalInterface")  
  15.   
  16. #endif // CALINTERFACE_H  
3>创建实现类Cal

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. #ifndef CAL_H  
  2. #define CAL_H  
  3.   
  4. #include <QObject>  
  5. #include "calinterface.h"  
  6.   
  7. class Cal : public QObject, public CalInterface  
  8. {  
  9.     Q_OBJECT  
  10.     Q_PLUGIN_METADATA(IID "org.qt-project.Qt.Examples.CalPlugin.Cal" FILE "CalPlugin.json")  
  11.     Q_INTERFACES(CalInterface)  
  12.   
  13. public:  
  14.     explicit Cal(QObject *parent = 0);  
  15.     int add(int a, int b);  
  16.     int substract(int a, int b);  
  17. };  
  18.   
  19. #endif // CAL_H  

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. #include "cal.h"  
  2.   
  3. Cal::Cal(QObject *parent)  
  4.     : QObject(parent)  
  5. {  
  6. }  
  7.   
  8. int Cal::add(int a, int b)  
  9. {  
  10.     return a + b;  
  11. }  
  12.   
  13. int Cal::substract(int a, int b)  
  14. {  
  15.     return a - b;  
  16. }  
编译默认生成的dll文件在安装目录的plugins子目录下面,等会我们需要将它拷贝出来。

5.调用插件

1>创建CalPluginTest对话框类型的应用程序,编译运行;

2>在CalPluginTest.exe所在目录下新建一个plugins子目录,将上面生成的CalPlugin.dll插件拷贝到plugins目录下;

3>直接在构造函数写测试代码如下:

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. #include "dialog.h"  
  2. #include "ui_dialog.h"  
  3. #include <QtWidgets>  
  4. #include "../CalPlugin/calinterface.h"  
  5.   
  6. Dialog::Dialog(QWidget *parent) :  
  7.     QDialog(parent),  
  8.     ui(new Ui::Dialog)  
  9. {  
  10.     ui->setupUi(this);  
  11.   
  12.     QDir dir(QCoreApplication::applicationDirPath() + "/plugins");  
  13.     foreach (QString filename, dir.entryList(QDir::Files)) {  
  14.         qDebug() << "path:" << dir.absoluteFilePath(filename);  
  15.         QPluginLoader loader(dir.absoluteFilePath(filename));  
  16.         CalInterface *pcal = qobject_cast<CalInterface*>(loader.instance());  
  17.         if (pcal) {  
  18.             int a = 12, b = 34;  
  19.             int addResult = pcal->add(a, b);  
  20.             int substractResult = pcal->substract(a, b);  
  21.             qDebug() << "add:" << addResult << ", substract:" << substractResult;  
  22.         } else {  
  23.             qDebug() << "error";  
  24.         }  
  25.     }  
  26. }  
  27.   
  28. Dialog::~Dialog()  
  29. {  
  30.     delete ui;  
  31. }

0 0