Qt开发Active控件:如何使用ActiveQt Server开发大型软件的主框架(2)
Qt开发Active控件:如何使用ActiveQt Server开发大型软件的主框架
注:本文更多地是带着如何去思考答案,而不是纯粹的放一个答案上来,如果你需要直接看到完整的答案,请直接看实例和最后的柳暗花明部分,里面由详细的注释可以解答你的问题。
前情提要:
Qt的进程间通信,以服务器的形式,手把手教你VS上进行Qt的COM、ActivedQt Server的开发,比保姆还保姆
本文提供两个实例:
ActiveQt Server COM服务器端:Qt_ActiveServer_Main
ActiveQt Active控件调用端:Client_ActiveServer_Demo
上文提到如何创建并调用一个Active控件,但是并不能完全满足我们的要求:现在我有一个主框架或者说主程序,会有很多别的模块需要在外部开发,这些模块可能会需要用到主框架中的信息,或者说一些接口来调用一些特定的功能。比如说我一个课堂教学模块,可能需要实现屏幕广播,语音广播,资料下发等功能。
如果你根据前文的实例进行我们根据上文的实例开发中会发现一个很明显的问题,那就是我们可以从调用方向主框架调用方法,但是却没法从主框架中发送消息给调用方。或者说如果这个COM服务器是有ui的,如果多个调用方可能就会调起多个界面,而且关闭调用方的同时会把这些界面都关闭,这又是怎么回事呢?为什么我们的ActiveServer不是像一个服务器一样简单地向其他的调用方提供服务?
关于这点,我翻遍了国内外几乎所有论坛和文章,以及Qt官方论坛和文章,发现并没有什么讨论的,或者零星有两个提问的人,但是都没有获得相关开发人员的回应。在这里我将会讨论上面的问题,并给出一套可行的方案。
一、当我们在创建一个ActiveQt Server的时候,我们在做什么。
由前文我们可以知道,我们建立一个Qt的COM组件,其实很简单,通过

这样一个宏就可以将一个类暴露在外,并且建立连接。然后我们可以拆分成如下形式:

--------------与以下形式---------------

我们在main函数内这么写了之后,我们就可以来调用了。这是我们在Qt的官方文档上看到的,也是我们能在几乎所有资料上看到的。
现在我们是不是建立了一个Active Server了呢?是的,你是建立了一个ActiveServer,但是现在这个ActiveServer只能单方面地提供服务,就像我上面说的那样:,那就是我们可以从调用方向主框架调用方法,但是却没法从主框架中发送消息给调用方。
这是为什么?我们要从创建开始说起。我们知道ActiveQt Server上是通过三个模块来实现ActiveServer的,我们可以从官方文档上看到:

第一个 第二个类你稍微看一下内容你就会发现,第一个类是为了提供一些额外接口,第二个类是用来提供与COM事件和绑定函数、参数的。真正用于运作整个ActiveServer的其实是QAxFactory
但是我们走进来看这个类的介绍,我们发现这个类里面全是提供的虚函数,我们应该会意识到这个类其实是一个基类,通过虚函数提供了一大堆的方法供其他组件去调用

聪明的你肯定想到了,那既然如此肯定是需要我们去继承这个QAxFactory类,然后来执行一些操作的吧!
等等,我们真的需要继承一个QAxFactory类(且不论能不能继承)吗?我们好像并没有见到一个QAxFactory的实例吧,那我们继承它又有什么用呢?(当然了,其实我是尝试继承了的,但是继承不了,这个单例会直接无法初始化了,还有些别的问题,这里就不一一分析了)
文档中没有提到,但是我在某个不记得的帖子上看到有人在说QAxFactory类提供了一个全局的单例qAxFactory(),于是我开始研究起了这个单例
经过一段时间对QAxFactory类的函数的研究,我发现这些函数其实没有多大用,并没有想到能解决什么问题的,于是问题又继续了下去。
有什么,不一样?
我们这个时候想到去比对一下,我们生成的ActiveServer和普通的Qt应用程序有什么不一样?聪明的你发现了,除了引用了QAxFactory.h之外,就是引用了这个宏:

----------------分割线-----------------

在中文
通过查找资料,你会发现Q_CLASSINFO宏只是给类提供了一个标识,并不是影响工作的关键。于是QAXFACTORY_BEGIN就理所应当的是我们查找的关键,让我们走到官方文档:(英文的就不放了,看着费劲,这里放个百度翻译吧)

这个好像和我之前讲的也没有什么关系,只是影响了声明导出和注册的类等信息,为了探寻真相,我们需要进一步走到QAxFactory.h内部去看发生了什么

这个宏好像就覆写一堆函数...有点意义不明,继续看下去,然后就想了一段时间....
想一下发生了什么
我们发现,每次一个外部进程用一个QAxObject来setControl一下我们的服务器,就会多一个窗口对吧。等等,多一个窗口?
为什么会多一个窗口?难道是创建了一个新的进程吗?不会啊,还记得我们的Main函数是怎么写的吗?

在我们的程序设计之初就考虑了不会让外部进程启动一个新进程的,所以不可能是新的进程导致的窗口启动的。
那就只有一个可能了,是一个新的类实例化了。我们将断点放到窗口类的构造函数上,我们发现断点被击中了!说明猜测是对的,类确实是被实例化了。
这样一切的疑问就解决了!为什么我们没法通信,因为信号根本就不是从这个实例发出的,而是从另外一个被外部调用绑定的实例啊!都不是一个对象而且没有进行绑定那肯定是没法通信的啊!
也就是说,每个QAxObject 绑定了与ActiveQtServer之间的连接的时候,都会实例化一个新的实例来专门处理这这两个进程之间的服务与连接。
现在的问题就很简单了,我们该如何找到这个被新建的实例?
我们可以根据调用堆栈找到,是通过这个QAxFactory类的某个实例调用了createObject。那么问题就从怎么建立连接变成了怎么找到这个QAxFactory的某个实例建立的,于是我又回到了对qAxFactory()的研究
介绍文档中是这么介绍QAxFactory类的:

我真的被这个文档疯狂误导,因为确实是调用了这个createObject 方法生成了一个实例(但是不是通过qAxObject进行的,后面会说),但是我硬是横竖看不懂怎么找到已经调用生成的实例我要去哪里找,唯一有点关系的就是这个featurList() (其实一点关系没有),搞了好久我觉得哪里有问题,就又回到qaxfactory.h里面去看,到底做了什么

这次不一样了,我看到一点不一样的东西,我们看到这个宏,初始化了一个QAxClass,这个类是什么?在Qt的官方文档上我居然没有找到,定睛一看,哦原来是这个.h文件里面声明的类,来看看内容

原来是提供了一个QAxFactory的模板子类,到这里我才明白,原来这是通过这个QAxClass的createObject来生成实例的。于是我开始尝试继承重写这个类
(过程不表了,反正搞了一个多小时我发现这个类其实是写在lib里面的改不了 囧)
ok重写是不行的,那肯定也和这个qAxFactory()的实例没有关系了,现在貌似又进了一个死胡同。
最后柳暗花明的是,我抱着试一试的态度问了下AI,它居然告诉我,你既然要记录实例化的对象,那你为什么不通过一个静态的QList,在每次这个类的对象实例化的时候将其记录在案。当你需要发送消息的时候,就可以从这个QList中读取想要的QObject,然后发送对应的信号,不就行了吗?
听罢,我惊为天人。于是就开始写
柳暗花明-总结
于是总的开发就这样结束了,把大概最后的框架描述一下就是
首先我们需要一个导出类A,这个类是暴露给外部的,提供接口给外部进程调用,这个类A需要继承QObject和QAxBindable,前者可以保证signals和slots的使用,后者可以保证signals和slots和COM函数和事件对接上。
然后我们要知道,外部每次调用setControl,其实都是实例化了一个导出类A,与这个实例之间进行信号交换。我们需要在这个类中声明一个静态数组,用于每次实例化这样一个对象的时候将所有的对象记录在案,以供调用。
然后我们可以通过一个总的COM管理类Main_Activerserver_Demo来管理这些实例化对象,比如让所有的对象发送消息

具体你想怎么操作都行,这里就不表了。
这里你可能会问,那我怎么让这个管理类Main_Activerserver_Demo接收外部进程的消息?它怎么知道信号什么时候来,怎么知道什么时候有新的实例会来?当然了,我们不知道,于是只能借助外部的一个信号中转站SignalCenter,并建立一个单例,以类似
的形式来广播通知让所有能看到SignalCenter的实例接收到消息...目前的想法是这样,也许后面会有更好的方案,但这个不是重点。
more?剩下的只有愉快的交流就完事了
Qt开发Active控件:如何使用ActiveQt Server开发大型软件的主框架(2)的更多相关文章
- CAD控件:QT开发使用控件入门
1. 环境搭建: 3 1.1. 安装Qt 3 1.2. 安装Microsoft Windows SDK的调试包 6 2. QT中使用MxDraw控件 7 1.3. 引入控件 7 3. 打开DWG文件 ...
- paper 139:qt超强绘图控件qwt - 安装及配置
qwt是一个基于LGPL版权协议的开源项目, 可生成各种统计图.它为具有技术专业背景的程序提供GUI组件和一组实用类,其目标是以基于2D方式的窗体部件来显示数据, 数据源以数值,数组或一组浮点数等方式 ...
- 用C#开发ActiveX控件,并使用web调用
入职差不多两个月了,由学生慢慢向职场人做转变,也慢慢的积累知识,不断的更新自己.最近的一个项目里边,涉及到的一些问题,因为SDK提供的只是winform才能使用了,但是有需求咱们必须得完成啊,所以涉及 ...
- IE8下调用Active控件
之前在IE6下运行正常的Active控件,浏览器升级到IE8后全部失效,并呈浏览器崩溃状. 网上搜了一圈得到如下解决方法: 1.设置信任站点 2.还需要在IE浏览器菜单 “工具>Internet ...
- ATL开发 ActiveX控件的 inf文件模板
ATL开发 ActiveX控件的 inf文件模板
- 使用C#开发ActiveX控件(新)
前言 ActiveX控件以前也叫做OLE控件,它是微软IE支持的一种软件组件或对象,可以将其插入到Web页面中,实现在浏览器端执行动态程序功能,以增强浏览器端的动态处理能力.通常ActiveX控件都是 ...
- IOS学习资源收集--开发UI控件相关
收集的一些本人了解过的iOS开发UI控件相关的代码资源(本文持续补充更新) 内容大纲: 1.本人在github上也上传了我分装好的一些可重复利用的UI控件 2.计时相关的自定义UILabel控件 正文 ...
- HMI开发与控件
=>控件是什么概念? 百度曰,控件是对数据和方法的封装.控件可以有自己的属性和方法.属性是控件数据的简单访问者. 对于HMI开发来说,使用控件可以快速获取到用户的交互(包括按下.释放.点击.拖动 ...
- [转]C#开发ActiveX控件,.NET开发OCX控件案例
引自:百度 http://hi.baidu.com/yanzuoguang/blog/item/fe11974edf52873aaec3ab42.html 讲下什么是ActiveX控件,到底有什么 ...
- Excel中的表单控件和active控件
EXCEL中有两种控件:表单控件和active控件 表单控件是excel5和excel95开始使用的,从excel97开始,active控件开始出现 关于表单控件和active控件的区别和使用范围,网 ...
随机推荐
- H5调用微信支付
这里用的是 vue项目; 首先在mounted中判断是否有openId,如果没有,则去获取 let openid = localStorage.getItem('openid'); if (!open ...
- PAT (Basic Level) Practice 1029 旧键盘 分数 20
旧键盘上坏了几个键,于是在敲一段文字的时候,对应的字符就不会出现.现在给出应该输入的一段文字.以及实际被输入的文字,请你列出肯定坏掉的那些键. 输入格式: 输入在 2 行中分别给出应该输入的文字.以及 ...
- 关于docker创建容器报错-docker: Error response from daemon: runtime "io.containerd.runc.v2" binary not installed
今天在对一台服务器(docker相关的业务服务器)进行OS补丁时,默认使用的 yum update -y 对所有的安装包进行了升级 升级完成后,让应用方检查确认应用及功能是否一切正常,如果不正常,严重 ...
- VM运行centos网络配置(出现错误)详解
一般按照正常安装流程到这一步的时候可以直接点击网络和主机名,但是我这里并没有连接成功,因此我跳过了这里想着后面再配置 后面通过ping www.baidu.com以及ping 百度的ip地址(如何获得 ...
- hmtl5 web SQL 和indexDB
前端缓存有cookie,localStorage,sessionStorage,webSQL,indexDB: cookie:有缺点 localStorage:功能单一 sessionStorage: ...
- Linux Block模块之deadline调度算法代码解析
1 总体说明 Deadline调度器对一个请求的多方面特性进行权衡来进行调度,以期望既能满足块设备扇区的顺序访问又能兼顾到一个请求不会在队列中等待太久导致饿死.Deadline调度器为了兼顾这两个方面 ...
- win10安装pip
Windows如何安装pip?请看下面方法: 1.搜索pip 2.点击下载文件. 3.下载压缩包 6.解压到桌面. 7.进入解压目录,按住Shift点击右键,选择打开powershell 8.执行py ...
- 消息队列之RabbitMQ介绍与运用
RabbitMQ 说明 本章,我们主要从RabbitMQ简介.RabbitMQ安装.RabbitMQ常用命令.RabbitMQ架构模式.RabbitMQ使用.Quick.RabbitMQPlus的使用 ...
- SpringCloud微服务实战——搭建企业级开发框架(四十七):【移动开发】整合uni-app搭建移动端快速开发框架-添加Axios并实现登录功能
uni-app自带uni.request用于网络请求,因为我们需要自定义拦截器等功能,也是为了和我们后台管理保持统一,这里我们使用比较流行且功能更强大的axios来实现网络请求. Axios ...
- jmeter执行报错:java.lang.UnsupportedClassVersionError解决办法
做个记录. 问题记录: jmeter版本:5.4.1 本地Java版本:1.8.0_151 执行jmeter,报错: 2022-10-14 12:06:27,372 ERROR o.a.j.JMete ...