导出Qt模块DLL给VC调用
本文于1891天之前发表,文中内容可能已经过时。
由于Qt的强大特性,在VC开发时一直想能否导出Qt的各个模块为VC所用,本文介绍一种思路,抛砖引玉下,经测试满足 VC 6.0及以上版本
起源
大家都知道MFC框架没有很好的数据库框架来用,而Qt的数据库模块简直不要太好用,于是就想能否来个乾坤大挪移呢?经过一阵乱撸,终于搞定!!!
借鉴思路
雨田哥的博客之 封装QtCore,于是想除了QtCore能否将Qt的数据库模块也导出来呢?答案是肯定的
实现步骤
分为两个部分:
- DLL模块
- 测试调用程序
DLL编写
先说下版本,为了方便的在Windows下调用,肯定使用MSVC版本的Qt,我电脑上装了Qt 4.8.0 VS 2010版本
- 新建Qt C++ library工程
偷巧的方法为先使用Qt Creator 创建一个DLL工程,然后再用VS插件打开进行编译,经测试需要在工程文件夹下建立include文件夹放入下列文件
1 | qsqldatabase.h qsqlerror.h qsqlrecord.h |
请注意,以上文件为真实的文件,一般在Qt安装目录下的corelib目录下(可以通过QtCreator跳转过去,一直找到真实的文件为止)
- 代码如下
头文件
1 | //qsqllib.h |
Cpp文件
1 | //代码 qsqllib.cpp |
测试调用程序
- 新建一个MFC工程
- 加入上一步中的导出头文件(见底部链接下载即可)
- 对用到的头文件拷贝到当前文件夹下来(对于 VC6.0来说,必须将文件编码转为assic版本,不然会报错)
- 找到对应版本的.lib文件拷贝到当前目录下lib文件夹下
- 编写代码,如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31#include "include/qsqllib.h"
void foo()
{
bool bok = false;
char dbName[255] = {0};
char type[20] = {0}; //"QSQLITE"
char host[20] = {0}; //"127.0.0.1",
char szPort[20] = {0};
char userName[50] = {0};
char passWd[50] = {0};
//......
CSql sql;
bok = sql.connectDataBase(dbName, type, host, atoi(szPort), userName, passWd);
if(!bok){
AfxMessageBox(sql.lastError().toLocal8Bit().constData());
return FALSE;
}
QSqlQuery query;
bok = sql.exec(&query, "select * from table");
if(bok){
while(query.next()){
TRACE("%d, %s\n", query.value(0).toInt(),query.value(1).toString().toLocal8Bit().constData());
}
}
}
经验
VC 6.0版本要求文件编码为ASSIC,Qt默认版本应该是 utf-8,所以可以通过notepad++转化,本人已经将所有的格式转化完毕,见附件头文件
对于编译错误先注释起来(为毛这样能行?因为对于DLL来说只要有个声明就行.h文件中声明的东西在对应的DLL中都已经实现了)
对于数据库提示Driver not loader错误,需要将sqldriver路径加入到库路径,见代码中的QCoreApplication::addLibraryPath();
数据库关闭错误说明见Qt数据库removeDatabase注意事项
在C语言的DLL中(本文未给出)其他版本的都OK,但是oracle老是在退出的时候崩溃,一阵乱撸之下发现有两种方法可以搞定(貌似是资源释放的问题),都不是很理想,于是就有了C++的class版本
方法1:(勉强可以接受)
1
2
3
4
5
6
7
8
9
10
11//用指针
QSqlQuery *query = new QSqlQuery();
bok = exec(query, "select * from table");
if(bok){
while(query->next()){
TRACE("%d, %s\n", query->value(0).toInt(),query->value(1).toString().toLocal8Bit().constData());
}
}
//这里要delete
delete query;方法2:(有点2)
1
2
3
4
5
6
7
8
9
10
11
12//用局部区域变量来自动释放
{
QSqlQuery query;
bok = exec(&query, "select * from table");
if(bok){
while(query.next()){
TRACE("%d, %s\n", query.value(0).toInt(), query.value(1).toString().toLocal8Bit().constData());
}
}
}
PS
也曾尝试将Gui相关的导出,比如QPixmap类,但是没有成功
更新
- GUI类也可以成功,比如QImage,可以直接使用, QPixmap类,需要在头文件中注释掉错误行即可
1
//Q_DECLARE_SHARED(QPixmap)
- 需要注意的是在使用GUI相关的类时会提示在使用前必须初始化QApplication
解决方案:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22//在实例化QPixmap之前调用实例化QApplication
void MFC_FOO()
{
int argc = 1;
char *argv[] = {
"foo"
};
QApplication a(argc, argv);
QPixmap pix;
pix.loadFromData(....);
//MFC 代码 ......
// .....
//不需要调用a的事件循环,嗯,就是这么浪..
}
下载链接
- 附件中的头文件链接在来一遍头文件
- 对于最难缠的oracle数据来说,OCI版本的DLL见oracle的oci驱动DLL
- OCI版本的DLL见oracle的oci驱动DLL分卷
您的支持是我前行的动力!