查看完整版本: [-- 导出Qt模块DLL给VC调用 --]

QTCN开发网 -> Qt代码秀 -> 导出Qt模块DLL给VC调用 [打印本页] 登录 -> 注册 -> 回复主题 -> 发表主题

spygg 2019-10-22 20:53

导出Qt模块DLL给VC调用


原文链接导出Qt模块DLL给VC调用



起源

大家都知道MFC框架没有很好的数据库框架来用,而Qt的数据库模块简直不要太好用,于是就想能否来个乾坤大挪移呢?经过一阵乱撸,终于搞定!!!


借鉴思路

雨田哥的博客封装QtCore,于是想除了QtCore能否将Qt的数据库模块也导出来呢?答案是肯定的


实现步骤

分为两个部分:
  1. DLL模块
  2. 测试调用程序


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
    qsqldriver.h    qsqlquery.h  qvariant.h
请注意,以上文件为真实的文件,一般在Qt安装目录下的corelib目录下(可以通过QtCreator跳转过去,一直找到真实的文件为止)
代码如下

头文件
  1. //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文件
  1. //代码 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();
    }


测试调用程序
  1. 新建一个MFC工程
  2. 加入上一步中的导出头文件(见底部链接下载即可)
  3. 对用到的头文件拷贝到当前文件夹下来(对于 VC6.0来说,必须将文件编码转为assic版本,不然会报错)
  4. 找到对应版本的.lib文件拷贝到当前目录下lib文件夹下
  5. 编写代码,如下
  1. #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());
            }
        }
    }

经验
  1. VC 6.0版本要求文件编码为ASSIC,Qt默认版本应该是 utf-8,所以可以通过notepad++转化,本人已经将所有的格式转化完毕,见附件头文件
  2. 对于编译错误先注释起来(为毛这样能行?因为对于DLL来说只要有个声明就行.h文件中声明的东西在对应的DLL中都已经实现了)
  3. 对于数据库提示Driver not loader错误,需要将sqldriver路径加入到库路径,见代码中的QCoreApplication::addLibraryPath();
  4. 数据库关闭错误说明见Qt数据库removeDatabase注意事项
  5. 在C语言的DLL中(本文未给出)其他版本的都OK,但是oracle老是在退出的时候崩溃,一阵乱撸之下发现有两种方法可以搞定(貌似是资源释放的问题),都不是很理想,于是就有了C++的class版本

方法1:(勉强可以接受)
  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)
  1. //用局部区域变量来自动释放
    {
        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








liulin188 2019-11-19 17:49
    

1003780259 2019-11-26 10:03
QT的代码要跑起来不是必须有一个QApplication的实例吗? 单独导出一个模块,不创建一个QApplication也能用啊?求指教!

spygg 2019-11-30 13:42
1003780259:QT的代码要跑起来不是必须有一个QApplication的实例吗? 单独导出一个模块,不创建一个QApplication也能用啊?求指教! (2019-11-26 10:03) 

依赖事件循环的才需要,比如显示模块

rpdhunter 2019-12-31 09:13
两个问题啊
一。为何还要用MFC,难道是旧项目维护?
二。为何用vc6.0,难道还是旧项目维护?

1003780259 2020-01-04 14:46
spygg:依赖事件循环的才需要,比如显示模块 (2019-11-30 13:42) 

哦哦,明白了,我之前用了通信模块的内容,是依赖事件循环的,谢谢回复!


查看完整版本: [-- 导出Qt模块DLL给VC调用 --] [-- top --]



Powered by phpwind v8.7 Code ©2003-2011 phpwind
Gzip disabled