前言

最近我们项目部的核心产品正在进行重构,然后又是年底了,除了开发工作之外项目并不紧急,加上加班时间混不够了....所以就忙里偷闲把整个项目的开发思路聊一下,以供参考。

鉴于接下来的一年我要进行这个主框架的开发,本着精益求精的态度,加上之前维护前辈的产品代码确实给我这个刚毕业的社畜带来了不小的震撼,我决定在这个模块的开发中优化之前的开发模式,提升整个产品的健壮性和独立性。

开发一个大型软件最重要的问题有三个,一是如何保证每个模块开发的独立性 二是如何保证数据结构的一致性 三是如何保证程序的可维护性和健壮性。这几个文章的内容我会在几篇文章中分开聊聊我的做法,做个记录。

本篇文章聊聊如何保证各个模块开发的独立性——怎么让功能模块、教学模块的开发独立于主框架本身。让不同的模块之间尽量通过接口的形式进行交互,而抛弃传统的中转消息码->调用模块的模式,让实际功能以接口形式暴露。

这一期来聊聊开发中遇到的一些问题:QtActive Server如何通过COM口传递自定义结构体?如何通过一个COM口来获得所有COM接口?

浏览本文前,请务必查看前置文章以获得更好的阅读体验,避免你不知道我在说什么:

Qt开发Active控件:如何使用ActiveQt Server开发大型软件的主框架

Qt开发:Windows 下进程间通信的可行桥梁:窗体消息

【大型软件开发】浅谈大型Qt软件开发(一)开发前的准备——在着手开发之前,我们要做些什么?

一、如何让ActiveServer的接口以树形结构暴露

就我在开发的过程中发现了一个问题,就我的命名格式是以类似sig_SeatManager_GetAllSeatInfo()这样的方式命名的,虽然看上去结构清晰,但是总的来说不够简洁。在面对长时间的开发和维护,一个COM类暴露的接口和信号可能直接多达上百个,这显然是极大的影响了程序的维护效率。也就是类似图下:几乎所有的功能模块都通过Kernel 去调用了,这显然是不合适的。

最好的情况肯定是:我们所有的功能都通过每个功能模块的单例去调用。然后每个暴露的接口都是根据各个不同的类分门别类来处理功能的,也就是说,每个类都能有一个自己单独的暴露COM接口的类型,Interface_Kernel类只需要提供向各个接口类的重定向就好。

那么怎么做呢?其实也很简单,COM接口除了最基本的数据类:

其实还可以直接传递指针,

注:这个似乎不一定要使用Q_PROPERTY注册相关的属性,当然了也不一定,需要自己去测试一下,我反正写完了我就懒得管了

Q_PROPERTY(SeatManager* GetSeatManager1 READ GetSeatManager)
SeatManager* GetSeatManager() {
this->test = &SeatManager::Singleton();
return this->test;
}

在调用方就可以这样调用:

Interface = new QAxObject();

if (!Interface->setControl("LBD_VS19.ILBD_CloudNetIntelClassroom.1")) {
//获取失败
this->Add("COM Interface Load Failed! Check ActiveQt Server is Exist.");
}
//用于获取SeatManager的指针
QAxObject* Interface2 = new QAxObject();
Interface2 = Interface->querySubObject("GetSeatManager1"); //获取SeatManager类的接口文档
QFile docs2("AX_Interfaces.html");
docs.open(QIODevice::ReadWrite | QIODevice::Text);
QTextStream TS2(&docs);
TS << str_interfaces << endl;

另外需要注意的一点是,这个SeatManager也需要在开头声明以下宏:

Q_OBJECT
Q_CLASSINFO("ClassID", "{2642F93D-069A-420C-A309-5E4F1808320B}")
Q_CLASSINFO("InterfaceID", "{20F4EA3B-A8AD-42C0-8AAA-1C97F1BD35CD}")
Q_CLASSINFO("EventsID", "{3C1458B9-C236-48BF-A9C0-2BEB0221C173}")
Q_CLASSINFO("RegisterObject", "yes")

但是这个SeatManager不需要继承QAxBindable类,因为这个类需要提供功能但是并不是直接对外暴露给系统去调用的。由上就可以通过一个接口将几乎所有的接口类全部通过COM接口及文档的方式暴露给客户,以供调用。

二、如何传递自定义结构体或者类

这个在网上也是没说,Qt的官方文档写的也是一坨稀烂,报的相关错误更是重量级。

一开始我想的是直接通过QVarirant类直接将我的自定义类型转换一下,比如类似使用Q_DECLARE_METATYPE(test_struct)这样的宏直接进行转换。但是在我多次尝试之后一直会报错

QAxBase: Error calling IDispatch member getvseat_info: Type mismatch in parameter -1

后来我才意识到,这样的数据可以在一个进程内部自由流动,但是QVariant定义了一个自定义结构是不能直接在COM接口之间自由流动的,这部分需要去稍微了解一下COM的定义及内部结构才能更好的明白,总之你只需要知道并不能在ActiveServer这边定义一个接口,然后在调用方去直接获得这个QVariant对象,然后再强制转换回来,这样的操作是非法的。

怎么做?

其实我们能有一个相当简单粗暴的方式,也是一个可以体现cpp优越性的方式:直接强行把对象转成二进制流,然后通过COM口返回,再让调用方去转换这个二进制流。

我们来看下代码,其实比较简单:

ActiveServer:

//在此转换结构体
QByteArray myStructMethod() {
QByteArray send;
send.resize(sizeof(test_struct)); std::memcpy(send.data(), &testinstance, sizeof(test_struct)); return send;
}

调用方:

resultarr = Interface->dynamicCall("getseat_info()").toByteArray();
SeatInfo* tseatinfo = (SeatInfo*)resultarr.data();

这样就是相当于把在ActiveServer中的一个类直接转换成QByteArray,然后发送给调用方去转换这个QByteArray

这个做法和Json的方式比,有优点也有缺点

优点:

使用方便,只需要两边有对其的头文件就可以直接转换类或者结构体,直接跨线程无损传递数据,比JSON方便得多还少很多步骤

缺点:

1.几乎是不可维护的,因为两边的类类型必须对齐,也就是说两边的数据类型都完全无法二次加工,最好是只存放数据,如果需要自定义的化只能自己新开一个类。

2.不同的语言之间不能协调,因为我们原来的这个类是继承了QObject类,如果我们换一种语言用不到QObejct,那么这个类就变成不可获取的接口了。

注:

尽管缺点非常明显,我们还是选择了使用此方式。

1.因为QObject类可以提供QJson和QObject的转换--详情看我的轮子QJson和QObject的转换--轮子,在面对不同语言时其实struct的兼容性也并不好,所以思来想去还是直接传指针算了,除了指针之外还需要另外提供一套Json的方法,以供一些非Qt的教学模块以及第三方的进程使用---并不是只有我们内部使用的东西,我们只提供JSON字符串!

2.不得不说,这样做可以极大的减少Qt开发子模块的工作量,也是我们主要重做这个框架的重要目的之一。

【大型软件开发】浅谈大型Qt软件开发(三)QtActive Server如何通过COM口传递自定义结构体?如何通过一个COM口来获得所有COM接口?的更多相关文章

  1. Qt 信号槽传递自定义结构体

    Qt 在信号和槽中使用自己定义的结构体

  2. [IC]浅谈嵌入式MCU软件开发之中断优先级与中断嵌套

    转自:https://mp.weixin.qq.com/s?__biz=MzI0MDk0ODcxMw==&mid=2247483680&idx=1&sn=c5fd069ab3f ...

  3. 浅谈大型web系统架构

    动态应用,是相对于网站静态内容而言,是指以c/c++.php.Java.perl..net等服务器端语言开发的网络应用软件,比如论坛.网络相册.交友.BLOG等常见应用.动态应用系统通常与数据库系统. ...

  4. 转:浅谈大型web系统架构

    浅谈大型web系统架构 动态应用,是相对于网站静态内容而言,是指以c/c++.php.Java.perl..net等服务器端语言开发的网络应用软件,比如论坛.网络相册.交友.BLOG等常见应用.动态应 ...

  5. 浅谈OA办公软件市场行情

    3.原文:http://www.jiusi.net/detail/472__776__3999__1.html 关键词:oa系统,OA办公软件 浅谈OA办公软件市场行情 中国的OA办公软件市场历经20 ...

  6. 【ZZ】浅谈大型web系统架构 | 菜鸟教程

    浅谈大型web系统架构 http://www.runoob.com/w3cnote/large-scale-web-system-architecture.html

  7. 浅谈关于QT中Webkit内核浏览器

    关于QT中Webkit内核浏览器是本文要介绍的内容,主要是来学习QT中webkit中浏览器的使用.提起WebKit,大家自然而然地想到浏览器.作为浏览器内部的主要构件,WebKit的主要工作是渲染.给 ...

  8. springboot开发浅谈 2021/05/11

    学习了这么久,本人希望有时间能分享一下,这才写下这篇浅谈,谈谈软件,散散心情. 这是本人的博客园账号,欢迎关注,一起学习. 一开始学习springboot,看了好多网站,搜了好多课程.零零落落学了一些 ...

  9. [原创]浅谈如何使用gcc开发NT核心驱动程序

    原文链接:[原创]浅谈如何使用gcc开发NT核心驱动程序 一谈到在 Win NT 下开发核心驱动程序,可能不少人首先都会想到微软“正统”的VC来.诚然,用VC 配合 WINDDK 的确工作的不错,但或 ...

  10. 【WebApi系列】浅谈HTTP在WebApi开发中的运用

    WebApi系列文章 [01]浅谈HTTP在WebApi开发中的运用 [02]聊聊WebApi体系结构 [03]详解WebApi参数的传递 [04]详解WebApi测试和PostMan [05]浅谈W ...

随机推荐

  1. 记录因Sharding Jdbc批量操作引发的一次fullGC

    周五晚上告警群突然收到了一条告警消息,点开一看,应用 fullGC 了. 于是赶紧联系运维下载堆内存快照,进行分析. 内存分析 使用 MemoryAnalyzer 打开堆文件 mat 下载地址:htt ...

  2. Python标准库之 xml.etree.ElementTree

    Element类型是一种灵活的容器对象,用于在内存中存储结构化数据. 每个element对象都具有以下属性: 1. tag:string对象,表示数据代表的种类. 2. attrib:dictiona ...

  3. ORCL 时间

    一.计算时间差 两个Date类型字段:START_DATE,END_DATE,计算这两个日期的时间差(分别以天,小时,分钟,秒,毫秒): 天: ROUND(TO_NUMBER(END_DATE - S ...

  4. 单一接口优化过程全记录(主要涉及Redis)

    接口优化过程记录 问题背景 某个接口耗时长(247ms),但里面逻辑不算复杂,只进行了简单的对象引用以及操作了多次Redis 步骤1:链路追踪,确定业务耗时点 接口里通过链路追踪以及日志查询发现主要是 ...

  5. 从零入门项目集成Karate和Jacoco,配置测试代码覆盖率

    解决问题 在SpringBoot项目中,如何集成Karate测试框架和Jacoco插件.以及编写了feature测试文件,怎么样配置才能看到被测试接口代码的覆盖率. 演示版本及说明 本次讲解,基于Sp ...

  6. 基于 Spring Cloud 的微服务脚手架

    基于 Spring Cloud 的微服务脚手架 作者: Grey 原文地址: 博客园:基于 Spring Cloud 的微服务脚手架 CSDN:基于 Spring Cloud 的微服务脚手架 本文主要 ...

  7. java中的instanceof方法

    本文主要讲述java中的instanceof()方法. 示例代码如下: public class InstanceTest { public static void main(String[] arg ...

  8. .Net执行SQL/存储过程之易用轻量工具

    支持.Net/.Net Core/.Net Framework,可以部署在Docker, Windows, Linux, Mac. 由于该工具近来被广东省数个公司2B项目采用,且表现稳定,得到良好验证 ...

  9. python Modbus 进行通讯时抛出Modbus Error: Exception code = 2

    源码: import modbus_tk from modbus_tk import modbus_tcp import modbus_tk.defines as cst PORT = 'com1' ...

  10. 一次TiDB GC阻塞引发的性能问题分析

    背景 前不久从项目一线同学得到某集群的告警信息,某个时间段 TiDB duration 突然异常升高,持续时间6小时左右,需要定位到具体原因. 分析过程 第一招,初步判断 由于项目条件苛刻,历经苦难才 ...