spygg |
2019-10-22 20:53 |
导出Qt模块DLL给VC调用
原文链接导出Qt模块DLL给VC调用 起源 大家都知道MFC框架没有很好的数据库框架来用,而Qt的数据库模块简直不要太好用,于是就想能否来个乾坤大挪移呢?经过一阵乱撸,终于搞定!!! 借鉴思路 雨田哥的博客之 封装QtCore,于是想除了QtCore能否将Qt的数据库模块也导出来呢?答案是肯定的 实现步骤 分为两个部分:
- DLL模块
- 测试调用程序
DLL编写 先说下版本,为了方便的在Windows下调用,肯定使用MSVC版本的Qt,我电脑上装了Qt 4.8.0 VS 2010版本 偷巧的方法为先使用Qt Creator 创建一个DLL工程,然后再用VS插件打开进行编译,经测试需要在工程文件夹下建立include文件夹放入下列文件
- qsqldatabase.h qsqlerror.h qsqlrecord.h
qsqldriver.h qsqlquery.h qvariant.h
请注意,以上文件为真实的文件,一般在Qt安装目录下的corelib目录下(可以通过QtCreator跳转过去,一直找到真实的文件为止) 代码如下 头文件
- //qsqllib.h
#ifndef QSQLLIB_H #define QSQLLIB_H
#include "include/qsqldatabase.h" #include "include/qsqlquery.h" #include "include/qsqldriver.h" #include "include/qsqlerror.h" #include "include/qsqlrecord.h" #include "include/qvariant.h"
#if defined(QSQLLIB_LIBRARY) #define QSQLLIBSHARED_EXPORT __declspec(dllexport) #else #define QSQLLIBSHARED_EXPORT __declspec(dllimport) #endif
class QSQLLIBSHARED_EXPORT CSql { public: CSql(); ~CSql();
bool exec( QSqlQuery *query, QString queryString); void closeDataBase(); bool connectDataBase(QString dbName, QString type = "QSQLITE", QString host = "127.0.0.1", int port = -1, QString userName = "", QString passWd = "");
QString lastError(); QStringList drivers(); QSqlDatabase *dataBase(); QSqlRecord tableInfo(QString table); QStringList tables(); private: QSqlDatabase m_db; QStringList m_tables; };
#if !defined(QSQLLIB_LIBRARY) #ifdef _DEBUG #pragma comment(lib, "lib/qSqlLibd.lib") #pragma comment(lib, "lib/QtSqld4.lib") #pragma comment(lib, "lib/QtCored4.lib") #else #pragma comment(lib, "lib/qSqlLib.lib") #pragma comment(lib, "lib/QtSql4.lib") #pragma comment(lib, "lib/QtCore4.lib") #endif #endif
#endif // QSQLLIB_H
CPP文件
- //代码 qsqllib.cpp
#include "qsqllib.h" #include <QCoreApplication> #include <QDir> CSql::CSql() { }
CSql::~CSql() { if(m_db.isOpen()){ closeDataBase(); } }
void CSql::closeDataBase() { { QString connectionName = m_db.connectionName(); m_db.close();
m_db = QSqlDatabase(); QSqlDatabase::removeDatabase(connectionName); } }
bool CSql::connectDataBase(QString dbName, QString type, QString host, int port, QString userName, QString passWd) { QCoreApplication::addLibraryPath(QDir::toNativeSeparators(QCoreApplication::applicationDirPath())); QCoreApplication::addLibraryPath(QDir::toNativeSeparators("./")); //关闭已有连接,将m_db重置 closeDataBase();
m_db = QSqlDatabase::addDatabase(type); m_db.setHostName(host); m_db.setPort(port); m_db.setUserName(userName); m_db.setPassword(passWd); m_db.setDatabaseName(dbName);
if (!m_db.open()) { //关闭数据库,必须这样.. closeDataBase(); return false; }
if(type.compare("QOCI") == 0 || type.compare("QODBC") == 0){ QStringList tl; QSqlQuery query; const QLatin1String tableQuery("select table_name from user_tables"); exec(&query, tableQuery); while (query.next()) { tl.append(query.value(0).toString()); } m_tables = tl; } else{ m_tables = m_db.tables(); } return true; }
QSqlDatabase *CSql::dataBase() { return &m_db; }
QSqlRecord CSql::tableInfo(QString table) { //开启事务 m_db.transaction(); QSqlRecord record = m_db.record(table); m_db.commit(); return record; }
QStringList CSql::tables() { return m_tables; }
QStringList drivers() { return QSqlDatabase::drivers(); }
bool CSql::exec( QSqlQuery *query, QString queryString) { bool bok = false; //开启事务 m_db.transaction(); if(!queryString.isEmpty()){ bok = query->exec(queryString); } else{ bok = query->exec(); } m_db.commit(); return bok; }
QString CSql::lastError() { return m_db.lastError().text(); }
测试调用程序
- 新建一个MFC工程
- 加入上一步中的导出头文件(见底部链接下载即可)
- 对用到的头文件拷贝到当前文件夹下来(对于 VC6.0来说,必须将文件编码转为assic版本,不然会报错)
- 找到对应版本的.lib文件拷贝到当前目录下lib文件夹下
- 编写代码,如下
- #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:(勉强可以接受)
- //用指针
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)
- //用局部区域变量来自动释放
{ 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类,但是没有成功(经测试可以成功, 使用前需要实例化QApplication) PPS
|
|