Qt 5.9.1、VS 2017创建DLL的互相调用

本文介绍了在Qt 5.9.1和Visual Studio 2017环境下,如何创建及互相调用MFC和Qt的DLL。通过实例展示了MFC DLL的创建与使用,以及Qt DLL在Qt工程中的应用。强调了面向对象在DLL中的重要性,以及业务逻辑层代码的可移植性原则。

1 背景知识

九年前,PSE(化学工程,过程系统工程)硕士毕业,由于整个研究生期间均使用Matlab做课题研究,并有幸帮助老师带了2年的Matlab实验课程。毕业那阵,正如我这个课题组的师兄所说,在化工中我的计算机水平是最强的,在计算机中我的化工水平也是最强的。可企业不需要这样的人,便陷入了找工作的尴尬期。找份工作先干着吧,受当时一句话”真正的程序员用C++”的影响,选择了VC++,由于无人指导,大概那个时候认为VC++就是C++吧。
由于第一个月只干了二十几天,到手工资900多点,于是彻底从朋友圈中消失了。为了这个爱好,也只有坚持了。看了N本关于C++的书籍,特别是那边号称Windows编程圣经的MFC C++Windows程序设计。经过几年努力,也用MFC C++弄出个不大不小的系统。虽说小,也具备了串口通信、数据库操作、报表打印等功能。
目前开始使用Qt,总舍不得丢掉MFC,虽然明知道使用Qt调用VS 写的DLL纯属于只是一部分很小的需求。然后走过必留痕迹,就把其记录下来。主要原因如下:

  1. Qt只能使用MFC导出的标准接口,无法使用MFC导出的类;
  2. MFC能够使用MFC导出的类;
  3. Qt能够使用Qt导出的类。

对于企业级应用,MFC应用也好、Qt也罢,若需使用DLL或plugin,如果DLL或plugin不能导出类,那么将失去面向对象的强大功能。想使用面向对象的方法将各模块进行清洗划分,几乎是不可能的。

过去MFC界面框架比较火,现在Qt如日中天,说不定那天又出现的Xt什么之类的框架,若想代码具有较高的可移植性,业务逻辑层代码尽量做到:

  • 使用标准的C++语法;
  • 使用C++标准库;
  • 尽量不用系统级接口,如Win32 API。
  • 尽量使用C++提供的技术,如线程技术进行流程管理。

把握了以上原则,业务层代码才可以在跨平台、跨界面框架做到100%重用。废话不说了,步入正题。

2 MFC 工程

本文不讲述如何使用VS解决方案管理工程,本文仅给出工程非默认配置或需要注意的地方。如果对此不熟悉,请参考百度,或跳过该章节,直接阅览感兴趣的部分。

2.1 MFC DLL创建

这里写图片描述

这里写图片描述

头文件“MFC_DLL.h”中代码如下:

// The following ifdef block is the standard way of creating macros which make exporting 
// from a DLL simpler. All files within this DLL are compiled with the MFC_DLL_EXPORTS
// symbol defined on the command line. This symbol should not be defined on any project
// that uses this DLL. This way any other project whose source files include this file see 
// MFC_DLL_API functions as being imported from a DLL, whereas this DLL sees symbols
// defined with this macro as being exported.
#ifdef MFC_DLL_EXPORTS
#define MFC_DLL_API __declspec(dllexport)
#else
#define MFC_DLL_API __declspec(dllimport)
#endif

#ifdef __cplusplus
extern "C"
{
#endif

    // This is an example of an exported variable(Can be used by MFC and Qt)
    extern MFC_DLL_API int nMFC_DLL;

    // This is an example of an exported function(Can be used by MFC and Qt).
    MFC_DLL_API int fnMFC_DLL(void);

#ifdef __cplusplus
}
#endif

// This class is exported from the MFC_DLL.dll(Only used by MFC)
class MFC_DLL_API CMFC_DLL {
public:
    CMFC_DLL(void);
    // TODO: add your methods here.

public:
    int add(int a, int b);
};

对应的cpp文件“MFC_DLL.cpp”代码如下:

// MFC_DLL.cpp : Defines the exported functions for the DLL application.
//

#include "stdafx.h"
#include "MFC_DLL.h"


// This is an example of an exported variable
MFC_DLL_API int nMFC_DLL = 32;

// This is an example of an exported function.
MFC_DLL_API int fnMFC_DLL(void)
{
    return 42;
}

// This is the constructor of a class that has been exported.
// see MFC_DLL.h for the class definition
CMFC_DLL::CMFC_DLL()
{
    return;
}

int CMFC_DLL::add(int a, int b)
{
    return a + b;
}


void hello()
{
//  ::MessageBox(NULL, "hello world!", "greeting", MB_OK);
}

int add(int a, int b)
{
    return a + b;
}

2 MFC Demo

这里写图片描述

2.3 MFC中DLL使用

头文件中添加如下语句:

#include "../MFC_DLL/MFC_DLL.h"
#pragma  comment(lib, "../../Bin/MFC_DLL.lib")

则可像工程本身一样使用DLL中的变量、函数和类:

void CMFC_DemoDlg::OnBnClickedButtonVariables()
{
    // TODO: Add your control notification handler code here
    CString str;
    str.Format(_T("%d"), nMFC_DLL);
    MessageBox(str, _T("Dll 中的变量"), MB_OK | MB_ICONINFORMATION);
}


void CMFC_DemoDlg::OnBnClickedButtonFunction()
{
    // TODO: Add your control notification handler code here
    CString str;
    str.Format(_T("%d"), fnMFC_DLL());
    MessageBox(str, _T("Dll 中的函数"), MB_OK | MB_ICONINFORMATION);
}


void CMFC_DemoDlg::OnBnClickedButtonClass()
{
    // TODO: Add your control notification handler code here
    CMFC_DLL dllClass;

    CString str;
    str.Format(_T("%d"), dllClass.add(5, 6));
    MessageBox(str, _T("Dll 中的类"), MB_OK | MB_ICONINFORMATION);
}

特别注意:
本文只关于能够导出类的DLL使用,至于标准C DLL不属于文本讨论的范畴。

3 Qt 工程

3.1 Qt DLL创建

这里写图片描述

头文件“qt_dll.h”内容如下:

#ifndef QT_DLL_H
#define QT_DLL_H

#include "qt_dll_global.h"

extern QT_DLLSHARED_EXPORT int nQt_DLL;

QT_DLLSHARED_EXPORT int fnQt_DLL(void);

class QT_DLLSHARED_EXPORT Qt_DLL
{

public:
    Qt_DLL();

public:
    int add(int a, int b);
};

#endif // QT_DLL_H

对应的cpp文件“qt_dll.cpp”代码如下:

#include "qt_dll.h"

// This is an example of an exported variable
int nQt_DLL= 62;

// This is an example of an exported function.
int fnQt_DLL(void)
{
    return 72;
}

Qt_DLL::Qt_DLL()
{
}

int Qt_DLL::add(int a, int b)
{
    return a + b;
}

3.2 Qt Demo创建

这里写图片描述

3.3 Qt Demo中使用Qt DLL

在pro文件中添加如下代码:

LIBS += ../../Bin/Qt_DLL.dll
INCLUDEPATH += ../Qt_DLL

在要使用的dll的文件头文件中添加如下代码:

#include "qt_dll.h"

则可以按下面的示例代码一样使用Qt dll中的变量、类:

void Widget::on_btnQtVariable_clicked()
{
    QMessageBox::information(this, QObject::tr("Qt DLL中的变量"), QObject::tr("%1").arg(nQt_DLL), QMessageBox::Ok);
}

void Widget::on_btnQtFunction_clicked()
{
    QMessageBox::information(this, QObject::tr("Qt DLL中的函数"), QObject::tr("%1").arg(fnQt_DLL()), QMessageBox::Ok);
}

void Widget::on_btnQtClass_clicked()
{
    Qt_DLL qtDll;
    QMessageBox::information(this, QObject::tr("Qt DLL中的类"), QObject::tr("%1").arg(qtDll.add(7, 8)), QMessageBox::Ok);
}

3.4 Qt Demo中使用MFC DLL

同3.3节一样,在pro文件中添加如下代码:

LIBS += ../../Bin/MFC_DLL.dll
INCLUDEPATH += ../MFC_DLL

在要使用DLL的文件中包含头文件:

#include "MFC_DLL.h"

则可以按下面的示例代码一样使用Qt dll中的变量、函数,但不能使用类:

void Widget::on_btnMFCVariable_clicked()
{
    QMessageBox::information(this, QObject::tr("MFC DLL中的变量"), QObject::tr("%1").arg(nMFC_DLL), QMessageBox::Ok);
}

void Widget::on_btnMFCFunction_clicked()
{
    QMessageBox::information(this, QObject::tr("MFC DLL中的函数"), QObject::tr("%1").arg(fnMFC_DLL()), QMessageBox::Ok);
}

4 结论

关于结论,前面已经提过,这里再次强调一下。
1. Qt只能使用MFC导出的标准接口,无法使用MFC导出的类;
2. MFC能够使用MFC导出的类;
3. Qt能够使用Qt导出的类。

注:
关于如何使用Qt、VS进行工程搭理,如将指定DLL、exe的生成一致的路径,添加文件的相对引用等内容不属于文本讨论的范畴。

示例代码的云盘路径:

链接: http://pan.baidu.com/s/1i502Us1 密码: 37vm

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值