利用回调函数实现DLL与Qt主程序的数据交互,进一步实现对Qt主程序中的信号触发
2018-02-23 10:23
746 查看
利用回调函数实现DLL与Qt主程序的数据交互,进一步实现对Qt主程序中的信号触发
Qt并没有提供串口通讯的接口,为了实现Qt程序的串口通讯,多数开发者都采用了一个第三方接口win_qextserialport。这个接口是完全基于Qt类库的,很容易就可以把它加载到自己的程序里边。但在实际应用过程中,发现了一个奇怪的现象:我的上位机程序是要通过控制串口(USB转的)来实现与下位机的通讯,经过测试,在相同的设置下,上位机程序和串口调试软件能够正常通讯,下位机和串口调试软件也能够正常通讯。按理说,这个时候上下位机也就应该能够正常地通讯了,但事实却很残酷:它们无法沟通,下位机接不到上位机的数据,上位机也接不到下位机的数据,----无论我如何调节相关设置、重新开关机,都无济于事。我不知道win_qextserialport到底怎么了,实在无暇去深究。因为时间比较紧,我不得不尽早尝试新的串口通讯接口。最直接的就是调用Windows API了,但那一堆堆冗长的接口函数实在繁琐。幸运的是有个大牛发布了一个C++串口通讯程序接口(CnComm.h头文件源代码,最新版是1.5),非常方便。因为它需要在VC下编译,所以我必须把它打包成DLL然后提供给Qt主程序调用。到这里,我面临很多的问题:1 大牛的接口是C++的,Qt可以容易地实现对DLL里的函数的调用,但如何调用Dll里的类?2 我需要在串口接收到数据后,把数据传回主程序,并马上在Qt主程序里释放一个信号(signal),以通知主程序处理。如何实现?3 DLL里根本不知道Qt主程序里的相关的类,更不知道Qt中的emit为何物,怎么传递Qt主程序里的类给他? 最后是通过回调函数来实现的。回调函数,就是把一个函数A的指针传递给另一个函数B,由函数B再调用函数A,这样就可以实现模块间的交互操作。如果再把函数A的指针传递给函数B的同时,也把相关的参数一起传递给函数B,那么就可以实现模块间的数据交互。例如:int sumit(int x, int y){
return x + y ;
}void testit(int a, int b, int (*func)(int, int))
{
QString strs = QString::number(func(a,b));
qDebug(strs.toAscii());
} 可以这样调用: testit(1,2,sumit);
打印输出值:3 下面是DLL与Qt主程序的主要实现代码:1 DLL代码#include "CnComm.h"
class communicate; //Qt中类的前向声明,通知DLL这是一个类
typedef void(*Emit)(communicate*, char*, int); //函数指针类型定义class HRComm : public CnComm
{
private:
Emit emitSignal ; //信号释放函数的指针, 用于指向回调函数
communicate * pComm; //Qt中类实例的指针,指向Qt主程序中的类实例,作回调函数的实参,以便在Qt主程序中进行信号释放 char *pDataBuffer; //接收数据缓存指针
int iLength; //接收到的字节数
void OnReceive() //重载接收函数
{
int dataLen = Read(pDataBuffer, iLength); //读取串口数据,返回实际接收的数据字节数
emitSignal(pComm,pDataBuffer,dataLen); //回调在此发生!传数据到到Qt主程序中,并把释放信号的类实例指针回传。
}public:
void SetSignal(communicate* commn, char *pData, int len, Emit func); //设置类参数, 把Qt主程序里的函数指针和其参数传到该串口通讯类中
}; void HRComm::SetSignal(communicate *commn, char *pData, int len, Emit func)
{
pDataBuffer = pData; iLength = len;
emitSignal = func; //传递Qt主程序里的函数(回调函数)指针
pComm = commn; //传递Qt主程序里的类实例指针
} HRComm hrComm; //实例化一个串口通讯类 bool openPort(int port, int baudrate)
{
return hrComm.Open(port, baudrate);
}
void closePort(void)
{
hrComm.Close();
}
void sendData(char *buff, int len)
{
hrComm.Write(buff, len);
}
void setReceiveSignal( communicate *commn,char *pData, int len, Emit pFunc)
{
hrComm.SetSignal(commn, pData, len, pFunc);
} Qt主程序通过调用openPort、closePort、sendData和setReceiveSignal分别实现打开串口、关闭串口、发送数据和回调函数传递。 2 Qt 主程序主要实现代码 1)communicate.h #ifndef COMMUNICATE_H
#define COMMUNICATE_H
#include "win_qextserialport.h"
#include <QObject>class Signal;
class QString;
class QByteArray;
class QLibrary; class communicate: public QObject
{
Q_OBJECT
public:
QLibrary *lib;
int iDataLen;
char *pData; communicate(QWidget *parent = 0);
Win_QextSerialPort *myCom;
int iPortNumber;
void Connect(void); bool b_checked;
void Open(int portNumber);
bool TestPort(int portNumber);
void SetSignalEmit(char *data, int len);signals:
void signalData(char *pData, int len);
public slots:
void Close(void);
void GotData(char *pData, int len);};#endif // COMMUNICATE_H 2)communicate.cpp#include "communicate.h"
#include "data.h"
#include <iostream>
#include <QLibrary>
typedef bool(*OpenPort)(int, int);
typedef void(*ClosePort)(void);
typedef void(*SendData)(char*, int);
typedef void(*SetSignal)(communicate*, char*, int, void(*pf)(communicate*, char*, int)); //回调函数。C++中,类成员函数不可以作回调函数,要不然就不用这么麻烦把communicate *comm传来传去了。
void SetIt(communicate *comm, char *data, int len)
{
qDebug("GOT DATA!");
QByteArray * bytes = new QByteArray;
for (int i=0; i<len;i++)
bytes->append(*(data+i));
qDebug(bytes->toHex());
comm->SetSignalEmit(data, len);
comm->b_checked = true;
} void communicate::Connect(void)
{
connect(myCom, SIGNAL(readyRead()),this,SLOT(readCom()));
}communicate::communicate(QWidget *parent)
{
b_checked = false;
strpc = SUNG_ID_CODE; iDataLen = 1024;
pData = new char[1024]; lib = new QLibrary("CommuModual.dll");
if(lib->load())
{
qDebug("dll is loaded");
}
else
qDebug("dll loading failed."); connect(this, SIGNAL(signalData(char*,int)),this, SLOT(GotData(char*,int)));}
void communicate::GotData(char*,int)
{ b_checked = true;
} void communicate::SetSignalEmit(char *data, int len)
{
emit this->signalData(data, len);
}void communicate::Open(int portNumber)
{
OpenPort openPort = (OpenPort)lib->resolve("openPort");
if (openPort)
{
qDebug("openPort loaded");
if(openPort(portNumber,115200))
qDebug("port opened");
else
qDebug("port opening failed.");
}
else
qDebug("openPort loading failed");}bool communicate::TestPort(int portNumber)
{
iPortNumber = portNumber;
SetSignal setSignal = (SetSignal)lib->resolve("setReceiveSignal");
if (setSignal)
{
qDebug("SetReceiveSignal loaded");
setSignal(this,this->pData, this->iDataLen,SetIt); //设置信号与回传
qDebug("Signal is set");
} Open(portNumber); //打开串口
SendData sendData = (SendData)lib->resolve("sendData");
if (sendData)
{
qDebug("sendData loaded");
QString strtemp = SUNG_ID_CODE;
int len = strtemp.count();
char *dt = new char[len+3];
*dt = 0xFF;
*(dt+1) = INST_ID_CODE;
for (int i=0; i<len;i++)
*(dt+i+2) = strtemp.at(i).toAscii();
*(dt+len+2) = 0xFF;
sendData(dt,len+3);
qDebug("data is sent");
Sleep(20);
delete []dt;
dt = NULL;
}
else
qDebug("sendData loading failed");
return b_checked;
}
void communicate::Close()
{
ClosePort closePort = (ClosePort)lib->resolve("closePort");
if (closePort)
{
qDebug("closePort loaded");
closePort();
qDebug("port is closed");
}
else
qDebug("closePort loading failed"); delete lib;
lib = NULL;} 3)main.cpp#include "communicate.h"void main(int argc, char *argv[])
{ communicate commn;
commn.TestPort(13); //测试:打开串口13,设置回调函数、数据传输参数 while(!commn.b_checked)
;
}
相关文章推荐
- 利用回调函数实现DLL与Qt主程序的数据交互,进一步实现对Qt主程序中的信号触发
- 利用PostMessage触发其他窗口类自定义消息响应函数实现主窗口和子窗口数据交互
- Native.js学习:利用Native.js实现Android与HTML数据的交互
- 线程共享的环境包括:进程代码段、进程的公有数据(利用这些共享的数据,线程很容易的实现相互之间的通讯)、进程打开的文件描述符、信号的处理器、进程的当前目录和进程用户ID与进程组ID。 进程拥有这
- 回调函数实现类似QT中信号机制
- 利用Ajax实现前端与.net后端实现数据交互
- 利用VC和ADO接口编写一个dll模块实现对数据库数据的处理
- 利用AjaxPro2实现前后台数据交互
- Qt 跨UI线程的数据交换和信号-槽调用实现方案汇总
- IFC标准是为了满足建筑行业的信息交互与共享而产生的统一数据标准,是建 筑行业事实上的数据交换与共享标准。本文概要介绍了IFC标准的产生及发展 历程,IFC的整体框架结构,简要说明了IFC标准的实现方法和过程,描述了 当前的应用以及我们应该更加积极地利用IFC标准为建筑软件行业服务。
- 利用ajax实现与php数据交互,并局部刷新页面
- flex父子页面数据交互实现(回调函数)
- iOS实战演练之关于数据交互的问题(利用XAMPP搭建本地服务器, 编写PHP代码实现iOS端注册登录功能)
- Android开发(11)-利用listview控件显示person表中的所有数据(并实现点击触发拨号程序)
- 利用Bmob云后端云函数实现移动应用与数据库的数据交互
- Qt中利用TCP实现客户端与服务器端的数据传输
- 利用ajax提交表单,实现数据前端后台数据交互的完整流程演示
- Android开发(11)-利用listview控件显示person表中的所有数据(并实现点击触发拨号程序)
- Qt实现两个非模态窗口的数据传递(信号与槽方式)
- flex4 父子页面数据交互实现(回调函数)