由于最近需要使用ActiveX,一般来说可以使用微软提供的MFC或者ATL框架来开发,由于我个人对这部分内容不是很熟悉,好在Qt也提供对于ActiveX的支持。本文主要记录个人学习ActiveX的一些内容,方便日后查阅。本文以Qt5(5.3.1)提供的ActiveX为参考,但是由于ActiveX这部分比较稳定,因此Qt4应该也是一样的。

概述

Qt提供了QtActiveX模块来支持微软ActiveX的开发,Qt的ActiveX和COM的开发支持两种方式:

支持将已有的COM或者ActiveX空间引入到Qt的应用程序中

支持将Qt应用程序或者Qt的对象导出成COM对象或者ActiveX控件供他人使用

具体来说,Qt是通过ActiveXQt框架中的两个模块来支持上述所说的两种方式的:

使用QAxContainer模块,通过QAxObject和QAxWidget分别支持COM对象和ActiveX控件的开发,可以通过这两个对象将外部的COM或者ActiveX组件接入到Qt应用程序

使用QAxServer模块,通过QAxAggregated、QAxBindable和QAxFactory类,通过了进程内和可执行程序exe两种方式的COM Server模式,用来将Qt写的内容导出为COM或者ActiveX供他人使用。

下图简要的说明了QtActiveX的作用

使用QtActiveX创建COM或ActiveX Server

在正式开始之前先对COM和ActiveX做一个简要的对比。COM(Component Object Model)是微软提出的一种技术,它定义了一种规范,通过COM可以轻松实现一种语言(如C#)调用另一种语言(如C++、VB等)开发的功能模块。ActiveX是微软主要针对互联网客户端设计的以COM为技术基础的一种实现,一般来说二者并没有本质的区别,仅有一些概念上的差异,一般来说:

1. ActiveX一般包含一个窗体界面,COM对象一般并没有界面

2. COM对象一般作为一个可调用的模块来使用,ActiveX一般嵌入在网页中使用

上述仅仅是一种使用上的惯例,但是并未强制一定这样

使用Qt作COM和ActiveX的开发需要使用QAxServer模块,这里面包含三个类:

1. QAxFactory定义了创建COM对象的工厂类

2. QAxBindable定义了COM对象与Qt对象之间的转换关系,也就是说Qt中的对象通过QAxBindable转换为COM中的要素

3. QAxAggregated定义了COM组件接口

Qt作为Server支持的模式

COM组件在开发出来之后有多种形式,可以是一个dll,也可以是一个exe可执行程序。可以在进程中被加载(一般最常用的模式),可以作为外部进程为其他进程提供服务,甚至可以是远程服务器上的进程为本地集成提供服务。Qt ActiveX 提供了In-Process和out-of-process executable两种方式的支持。简单来说就是提供了一种 Dll供应用程序调用也提供了一种可以作为运行的exe,为其他应用提供一些调用服务。

当作为独立exe时候,我们需要这样编写.pro文件:

TEMPLATE = app

QT += axserver

RC_FILE = qaxserver.rc当作为进程内dll的时候,需要这样写.pro文件

TEMPLATE = lib

QT += axserver

CONFIG += dll

DEF_FILE = qaxserver.def

RC_FILE = qaxserver.rc

...但是我们不用去操心这些内容,因为一般我们是用向导来生成Qt工程的,当你勾选ActiveX Server模式的时候,向导已经帮你写好这些内容了。

当使用QAxServer开发dll时,实际工程编译链接过程中会涉及到以下的过程:

1. 应用程序将会链接到qtserver.lib而不是qtmain.lib

2. idc工具会被调用,产生IDL文件(接口描述语言的接口描述文件)

3.调用MIDL工具编译IDL文件到类型库

4.调用idc工具将类型库附到server的二进制代码中

5. 注册dll

另外在.Pro文件中可以添加一个版本信息,这个版本信息会作类型库和server dll的版本号,添加方式使用VERSION变量即可:

TEMPLATE = lib

VERSION = 2.5

...

COM进程外和进程内使用方式的比较

进程外的使用方式是将COM写成一个exe可执行文件,当它运行的时候其他程序可以调用它提供的接口来开发,这样做如果某个调用它的程序出了bug,那么只有该程序会崩溃,其他调用不收影响,提供了更好的隔离性。缺点是需要更长的启动时间与跨进程通信的一些额外负担。

进程内的使用方式就很简单了,调用过程仅仅是通过类似虚函数这样的调用,需要加载的时间短、效率比较高。

开发Server的过程

为了使用Qt实现COM对象,我们必须使用一个QObject的子类,如果该子类是QWidget的子类,那么这个COM对象就是一个ActiveX控件。代码如下:

#include

class MyActiveX : public QWidget

{

Q_OBJECT只里面Q_OBJECT宏不能少,它提供了关于类MyActiveX的一些元数据信息, 接下来继续添加ActiveX的一些信息

Q_CLASSINFO("ClassID", "{1D9928BD-4453-4bdd-903D-E525ED17FDE5}")

Q_CLASSINFO("InterfaceID", "{99F6860E-2C5A-42ec-87F2-43396F4BE389}")

Q_CLASSINFO("EventsID", "{0A3E9F27-E4F1-45bb-9E47-63099BCCD0E3}")Q_CLASSINFO定义了COM组件的一些信息,这里面ClassID和InterfaceID是必须的,当你需要使用COM中的事件时,EventsID就需要添加进来。里面的128位的字符串使用GUID.exe工具生成(微软提供的一个小工具,可以生成全球唯一的标识符,可以在系统文件夹或者visual Studio的工具菜单中找到),工具提供了多种模式,可以选择需要的模式复制添加到代码中:

除了上述基本必要的信息之外(ClassID实际上被写入注册表中,当控件被使用的时候会搜索注册表找到里面该COM控件dll的位置并加载,可以使用regedit.exe在HKEY_CLASSES_ROOT中找到很多已经注册的COM组件信息),Qt还提供了Q_CLASSINFO更多的内容,如下表所示:

名称

值和含义

Version

类的版本号,默认值是1.0

Description

类的描述

ClassID

类的ID(COM中用来唯一确定一个类的方式)

InterfaceID

接口ID(COM中用来唯一确定接口的方式)

EventsID

事件ID

DefaultProperty

默认属性

DefaultSignal

默认的时间

LicenseKey

类的许可号,默认未开启,如果开启使用类需要许可号

StockEvents

TODO:???

ToSuperClass

暴露父类的接口

Insertable

设置"yes"后可以被列到OLE2容器中,默认未设置

Aggregatable

默认是"yes",COM支持聚合

Creatable

设置为“no”调用者不能使用该类

RegisterObject

仅能用在进程外方式的COM中

MIME

该COM控件支持的文件格式描述

CoClassAlias

类的名称在IDL中被修改为CoClassAlias指定的名字

继续上面的代码,接下来可以添加一些属性到COM组件中,可以使用另一个宏Q_PROPERTY

Q_PROPERTY(int value READ value WRITE setValue)之后可以像写Qt程序那样来完成。

public:

MyActiveX(QWidget *parent = 0)

...

int value() const;

public slots:

void setValue(int v);

...

signals:

void valueChange(int v);

...

};Qt的ActiveX框架会将Qt类中的要素转换为COM中的标准要素供其他调用者使用,具体来说:

1.  Qt类中的属性和公有的插槽函数(slots)会被转换为COM中的属性和方法

2.  Qt类中的信号(signals)会被转换成为COM组件中的事件

另外其他的数据类型转换之间的对应关系如下图所示:

1. Qt中属性的数据类型与COM中数据类型的转换关系如下:

Qt数据类型

COM 属性数据类型

bool

VARIANT_BOOL

QString

BSTR

int

int

uint

unsigned int

double

double

qlonglong

CY

qulonglong

CY

QColor

OLE_COLOR

QDate

DATE

QDateTime

DATE

QTime

DATE

QFont

IFontDisp*

QPixmap

IPixtureDisp*

QVariant

VARIANT

QVariantList

SAFEARRAY(VARIANT)

QStringList

SAFEARRAY(BSTR)

QByteArray

SAFEARRAY(BYTE)

QRect

User defined type

QSize

User defined type

QPoint

User defined type

2. Qt中信号和插槽函数的形式参数数据类型

Qt数据类型

对应COM的数据类型

bool

[in] VARIANT_BOOL

bool&

[in,out] VARIANT_BOOL*

QString, const Qtring&

[in] BSTR

QString&

[in, out] BSTR*

QStinrg&

[in, out] BSTR*

int

[in] int

int&

[in, out]int

uint

[in,out]unsigned int

uint&

[int, out] unsigned int*

double

[in] double

QColor, const QColor&

[in] OLE_COLOR

QColor&

[in,out] OLE_COLOR*

QDate, const QDate&

[in] DATE

QDate&

[in,out]DATE*

QDateTime, const QDateTime&

[in] DATE

QDateTime&

[in,out]DATE*

QFont, const QFont&

[in] IFontDisp*

QFont&

[in,out]IFontDisp**

QPixmap, const QPixmap&

[in]IPictureDisp*

QPixmap&

[in,out]IPictureDisp**

QList

[in]SAFEARRAY(VARIANT)

QList&

[in,out]SAFEARRAY(VARIANT)*

QObject*

[in] IDispatch*

此外QActiveX也可以通过Q_ENUMS和Q_FLAGS将枚举变量导出,如果使用了非上表中的类型来作为信号和插槽函数的参数类型,那么Qt ActiveX框架不会转换这些参数。

发布COM控件

为了让Qt编写的代码可以作为一个COM组件被使用,必须提供获取COM对象的方法,在Qt中使用QAxFactory来完成,最简单的方法是使用下面的宏:

QAXFACTORY_BEGIN("{ad90301a-849e-4e8b-9a91-0a6dc5f6461f}",

"{a8f21901-7ff7-4f6a-b939-789620c03d83}")

QAXCLASS(MyWidget)

QAXCLASS(MyWidget2)

QAXTYPE(MySubType)

QAXFACTORY_END()上面这段代码把MyWidget和MyWidget2导出为可供外部调用的COM对象,并注册MySubType类型可供MyWidget和MyWidget2中的属性和参数使用。

进程外COM控件的编写

对于进程外可执行的COM组件,我们需要执行一个main函数来实例化一个QApplication,和一般的Qt程序类似。

#include

#include

int main(int argc, char *argv[])

{

QApplication app(argc, argv);

if (!QAxFactory::isServer()) {

// create and show main window

}

return app.exec();

}

qt编写activex_Qt中使用ActiveX(一)相关推荐

  1. Qt编写自定义控件29-颜色选取面板

    一.前言 这个控件主要是模仿QColorDialog对话框中的颜色选取面板,提供一个十字形状的标识器,鼠标按下开始选取颜色,移动到哪就选择该处的颜色值,对应右侧颜色条放大显示,本控件的难点就是如何绘制 ...

  2. Qt编写项目作品大全(自定义控件+输入法+大屏电子看板+视频监控+楼宇对讲+气体安全等)...

    一.自定义控件大全 (一).控件介绍 超过150个精美控件,涵盖了各种仪表盘.进度条.进度球.指南针.曲线图.标尺.温度计.导航条.导航栏,flatui.高亮按钮.滑动选择器.农历等.远超qwt集成的 ...

  3. Qt编写自定义控件4-旋转仪表盘

    前言 旋转仪表盘,一般用在需要触摸调节设置值的场景中,其实Qt本身就提供了QDial控件具有类似的功能,本控件最大的难点不在于绘制刻度和指针等,而在于自动计算当前用户按下处的坐标转换为当前值,这个功能 ...

  4. Qt编写自定义控件44-天气仪表盘

    一.前言 天气仪表盘控件是所有控件中唯一一个使用了svg矢量图的控件,各种天气图标采用的矢量图,颜色变换采用动态载入svg的内容更改生成的,其实也可以采用图形字体来做,本次控件为了熟悉下svg在Qt中 ...

  5. Qt编写自定义控件3-速度仪表盘

    前言 速度仪表盘,写作之初的本意是用来展示当前测试的网速用的,三色圆环+数码管显示当前速度,Qt自带了数码管控件QLCDNumber,直接集成即可,同时还带有动画功能,其实也可以用在汽车+工业领域等, ...

  6. Qt编写自定义控件14-环形进度条

    前言 环形进度条,用来展示当前进度,为了满足大屏UI的需要特意定制,以前有个叫圆环进度条,不能满足项目需要,只能重新定做,以前的进度间距不能自适应分辨率,而且当前进度对应的反的进度不能单独设置颜色,即 ...

  7. Qt编写控件属性设计器4-加载属性

    一.前言 控件能加载拖曳拉伸了,这些都是基本的前提工作,接下来的重点就是要动态加载选中控件的属性了,Qt的属性机制那是异常的强大,只能用强大到爆来形容,Qt中编写自定义控件,如果属性都用Q_PROPE ...

  8. Qt编写自定义控件35-GIF录屏控件

    一.前言 在平时的写作过程中,经常需要将一些操作动作和效果图截图成gif格式,使得涵盖的信息更全面更生动,有时候可以将整个操作过程和运行效果录制成MP4,但是文件体积比较大,而且很多网站不便于上传,基 ...

  9. Qt编写控件属性设计器

    一.前言 自从研究Qt编写自定义控件以来,一发不可收拾,越多越多人有类似的需求找我定制控件,陆陆续续写了上百个控件,目前已超过150个,于是逐渐衍生了另外一个需求,提供一个控件属性设计器,类似QtDe ...

最新文章

  1. R语言dplyr包的top_n函数返回dataframe或tibble的前N行数据、dplyr包的top_frac函数返回dataframe或tibble的前百分之N(N%)的数据
  2. Tensorflow— tensorboard网络运行
  3. 二维随机变量期望公式_MIT 6.041 概率论笔记 离散随机变量(二)
  4. 5G全球声量升级:Verizon宣布固定+移动齐步走,中国第三阶段试验倒计时
  5. c语言运行时隐藏dos窗口
  6. Java中Comparable与Comparator的区别
  7. telnet命令---Linux学习笔记
  8. beta版本项目冲刺
  9. CSS 与 HTML5 响应式图片
  10. 在JS方法中返回多个值的三种方法
  11. 一步一步学Silverlight 2系列(8):使用样式封装控件观感
  12. NPM流行包再起波澜:维护人员对俄罗斯用户发特定消息,谁来保证开源可信?...
  13. 华胜天成以精益服务为中国联通构建电子渠道容灾系统
  14. html5 最小化,当前界面最小化快捷键 窗口最小化和全屏化的快捷键是什么?
  15. 新浪微博生成超短链接
  16. QuickFlow-如何通过QFD and ExecuteCode获取其他列表数据
  17. 论如何使用Python进行微信公众号的开发
  18. 国瀚实业|个人如何投资理财
  19. 我所认识的Thayer博士
  20. 长沙有哪些牛逼的互联网公司?看完我想回长沙了!

热门文章

  1. tensorflow 就该这么学--1
  2. MATLAB实战应用案例:欧拉法、改进欧拉法、ode45求解微分方程实例
  3. MATLAB实战系列(十八)-遗传算法解决TSP(旅行商)问题-算法原理
  4. 数据挖掘十大算法--K-均值聚类算法
  5. Python安装模块出错(ImportError: No module named setuptools)解决方法
  6. c++vector替换元素_从发展来看Vector与Hashtable的淘汰
  7. QT,QVector 基本用法,遍历[实例讲解]
  8. 大数据分析之Hadoop
  9. 分布式系统中的限流与熔断
  10. 不用copy代码--eclipse使用git提交项目-转