前言

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

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

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

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

这一期来聊聊开发中遇到的一些问题: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. day10-Tomcat02

    Tomcat02 4.IDEA开发JavaWeb工程 4.1开发javaweb工程&配置Tomcat&启动项目 需求:使用idea开发javaweb工程fishWeb,并将网页部署到f ...

  2. Vue2基础知识学习

    Vue2基础知识学习 01.初识 new Vue({ el: '#root', //用于指定当前Vue实例为哪个容器服务,值通常为css选择器符 data () { return { } } }); ...

  3. 从0到1搭建redis6.0.7续更~

    "心有所向,日复一日,必有精进" 前言: 想必大家看完我之前写的搭建redis服务器,大家都已经把redis搭建起来了吧如果没有搭建起来的小可爱请移步这里哦从0到1搭建redis6 ...

  4. AR空间音频能力,打造沉浸式声音体验

    随着元宇宙的兴起,3D虚拟现实广泛引用,让数字化信息和现实世界融合,目前大家的目光主要聚焦于视觉交互层面,为了在虚拟环境中更好的再现真实世界的三维空间体验,引入听觉层面必不可少,空间音频孕育而生. 空 ...

  5. SpringBoot3正式版将于11月24日发布:都有哪些新特性?

    从 2018 年 2 月 28 号发布 Spring Boot 2.0 版本开始,整个 2.X 版本已经经过了 4 年多的时间,累计发布了 95 个不同的版本,而就在前不久,2.X 系列的也已经迎来了 ...

  6. .net随笔——Web开发config替换到正式config appSettings

    前言(废话) 查了一些资料,总体来说呢,就是坑,而且顺带吐槽下百度,一个内容被copy那么多遍还排在最前面.同一个内容我点了那么多次,淦. 正题: 实现目的:开发的时候使用system.debug.c ...

  7. go get 报错:dial tcp 142.251.43.17:443: i/o timeout

    自动下载 go env -w GO111MODULE=on 设置环境为国内代理 go env -w GOPROXY=https://goproxy.cn,direct 注:go 版本需要支持 mod

  8. Servlet面试题合集

    servlet的生命周期 在创建servlet对象时,通过调用.init()方法进行初始化 通过service()方法来接收客户端的请求.根据请求方式的不同转发给对应的doGet()或doPost() ...

  9. vue3 + element plus 使用字节跳动图标

    使用场景: 提一下vue2 用法>> 下面回到正题 vue3 用法 1  安装包: npm install @icon-park/vue-next --save 2  字节跳动图标库取图地 ...

  10. Maven工程卡在Resolving Maven dependencies,长时间不变

    添加:-Xms1024m -Xmx2048m 点apply.ok 秒解决