1.隐式调用
1>新建一个C++库,工程名为Cal,自动生成三个文件cal.h, cal_global.h, cal.cpp,编译后生成我们需要的Cal.lib, Cal.dll
#ifndef CAL_H
#define CAL_H
#include "cal_global.h"
class CALSHARED_EXPORT Cal
{
public:
Cal();
int add(int a, int b);
int substract(int a, int b);
};
#endif // CAL_H
#include "cal.h"
Cal::Cal()
{
}
int Cal::add(int a, int b)
{
return a + b;
}
int Cal::substract(int a, int b)
{
return a - b;
}
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
我们在构造函数里面测试,代码如下:
#include "dialog.h"
#include "ui_dialog.h"
#include "cal.h"
#include <QDebug>
Dialog::Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog)
{
ui->setupUi(this);
Cal cal;
int a = 100, b = 200;
int addResult = cal.add(a, b);
int substractResult = cal.substract(a, b);
qDebug() << "add:" << addResult << ",substract:" << substractResult;
}
Dialog::~Dialog()
{
delete ui;
}
编译完成之后,将Cal.dll文件拷贝到生成的CalTest.exe目录下运行即可。
隐式调用用起来比较方便,但是不太灵活,如果缺少头文件,库文件那么这个程序就编译,执行不了了。
2.显示调用
Cal工程代码如下:
#ifndef CAL_H
#define CAL_H
#include "cal_global.h"
class CALSHARED_EXPORT Cal
{
public:
Cal();
int add(int a, int b);
int substract(int a, int b);
};
extern "C" CALSHARED_EXPORT Cal* createCal();
extern "C" CALSHARED_EXPORT void deleteCal(Cal *cal);
#endif // CAL_H
#include "cal.h"
Cal::Cal()
{
}
int Cal::add(int a, int b)
{
return a + b;
}
int Cal::substract(int a, int b)
{
return a - b;
}
Cal* createCal()
{
return new Cal();
}
void deleteCal(Cal *cal)
{
delete cal;
cal = NULL;
}
CalTest调用的时候,CalTest.pro里就不需要
INCLUDEPATH += $${PWD}/lib/cal
LIBS += $${PWD}/lib/cal/Cal.lib
这两行代码了,直接看cpp文件
#include "dialog.h"
#include "ui_dialog.h"
#include <QDebug>
#include <QLibrary>
#include "../Cal/cal.h"
Dialog::Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog)
{
ui->setupUi(this);
typedef Cal* (*CreateCal)();
typedef void (*DeleteCal)(Cal *cal);
QLibrary lib("Cal.dll");
if (lib.load()) {
CreateCal createCal = (CreateCal)lib.resolve("createCal");
DeleteCal deleteCal = (DeleteCal)lib.resolve("deleteCal");
if (createCal && deleteCal) {
Cal *pcal = createCal();
int a = 100, b = 200;
int addResult = pcal->add(a, b);
int substractResult = pcal->substract(a, b);
qDebug() << "add:" << addResult << ",substract:" << substractResult;
deleteCal(pcal);
} else {
qDebug() << "resolve failed";
}
lib.unload();
} else {
qDebug() << "load failed";
}
}
Dialog::~Dialog()
{
delete ui;
}
#include "../Cal/cal.h"头文件还是需要的,因为我们不知道Cal类是怎么声明的。
这样当这个dll不存在的时候我们的程序还是可以通过编译运行的。
但是这里还存在问题,Cal类我们还是导出了,因为我们演示的是一个比较简单的类,如果这个类比较复杂那么导出就有麻烦了,因为导出类的父类和子类也要导出,所以我们希望这个类不导出也可以使用。
3.纯虚基类,不导出类,通过虚表来定位具体的函数
Cal工程代码
#ifndef CALINTERFACE_H
#define CALINTERFACE_H
#include "cal_global.h"
class CalInterface
{
public:
virtual ~CalInterface() {}
virtual int add(int a, int b) = 0;
virtual int substract(int a, int b) = 0;
};
extern "C" CALSHARED_EXPORT CalInterface* createCal();
extern "C" CALSHARED_EXPORT void deleteCal(CalInterface *cal);
#endif // CALINTERFACE_H
#include "CalInterface.h"
#include "cal.h"
CalInterface* createCal()
{
return new Cal();
}
void deleteCal(CalInterface *cal)
{
delete cal;
cal = NULL;
}
#ifndef CAL_H
#define CAL_H
#include "cal_global.h"
#include "CalInterface.h"
class Cal : public CalInterface
{
public:
Cal();
virtual ~Cal();
virtual int add(int a, int b);
virtual int substract(int a, int b);
};
#endif // CAL_H
Cal.cpp内容和上面一样
CalTest工程调用:
#include "dialog.h"
#include "ui_dialog.h"
#include <QDebug>
#include <QLibrary>
#include "../Cal/CalInterface.h"
Dialog::Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog)
{
ui->setupUi(this);
typedef CalInterface* (*CreateCal)();
typedef void (*DeleteCal)(CalInterface *cal);
QLibrary lib("Cal.dll");
if (lib.load()) {
CreateCal createCal = (CreateCal)lib.resolve("createCal");
DeleteCal deleteCal = (DeleteCal)lib.resolve("deleteCal");
if (createCal && deleteCal) {
CalInterface *pcal = createCal();
int a = 100, b = 200;
int addResult = pcal->add(a, b);
int substractResult = pcal->substract(a, b);
qDebug() << "add:" << addResult << ",substract:" << substractResult;
deleteCal(pcal);
} else {
qDebug() << "resolve failed";
}
lib.unload();
} else {
qDebug() << "load failed";
}
}
Dialog::~Dialog()
{
delete ui;
}
这样Cal类就不必要导出了,而且CalInterface.h头文件是比较独立的,不依赖于其他的一些东西。
C++调用方法跟这类似,只是将QLibrary换成了LoadLibrary,GetProcAddress。
4.插件编写(lower-level api)
1>创建C++库,类型选择Qt Plugin,名称CalPlugin,删掉自动生成的genericplugin.h和genericplugin.cpp两个文件
2>创建接口类头文件calinterface.h
#ifndef CALINTERFACE_H
#define CALINTERFACE_H
#include <QtPlugin>
class CalInterface
{
public:
virtual ~CalInterface() {}
virtual int add(int a, int b) = 0;
virtual int substract(int a, int b) = 0;
};
Q_DECLARE_INTERFACE(CalInterface, "org.qt-project.Qt.Examples.CalPlugin.CalInterface")
#endif // CALINTERFACE_H
3>创建实现类Cal
#ifndef CAL_H
#define CAL_H
#include <QObject>
#include "calinterface.h"
class Cal : public QObject, public CalInterface
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.Examples.CalPlugin.Cal" FILE "CalPlugin.json")
Q_INTERFACES(CalInterface)
public:
explicit Cal(QObject *parent = 0);
int add(int a, int b);
int substract(int a, int b);
};
#endif // CAL_H
#include "cal.h"
Cal::Cal(QObject *parent)
: QObject(parent)
{
}
int Cal::add(int a, int b)
{
return a + b;
}
int Cal::substract(int a, int b)
{
return a - b;
}
编译默认生成的dll文件在安装目录的plugins子目录下面,等会我们需要将它拷贝出来。
5.调用插件
1>创建CalPluginTest对话框类型的应用程序,编译运行;
2>在CalPluginTest.exe所在目录下新建一个plugins子目录,将上面生成的CalPlugin.dll插件拷贝到plugins目录下;
3>直接在构造函数写测试代码如下:
#include "dialog.h"
#include "ui_dialog.h"
#include <QtWidgets>
#include "../CalPlugin/calinterface.h"
Dialog::Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog)
{
ui->setupUi(this);
QDir dir(QCoreApplication::applicationDirPath() + "/plugins");
foreach (QString filename, dir.entryList(QDir::Files)) {
qDebug() << "path:" << dir.absoluteFilePath(filename);
QPluginLoader loader(dir.absoluteFilePath(filename));
CalInterface *pcal = qobject_cast<CalInterface*>(loader.instance());
if (pcal) {
int a = 12, b = 34;
int addResult = pcal->add(a, b);
int substractResult = pcal->substract(a, b);
qDebug() << "add:" << addResult << ", substract:" << substractResult;
} else {
qDebug() << "error";
}
}
}
Dialog::~Dialog()
{
delete ui;
}