《COM原理与应用》学习笔记二——COM对象和COM接口的实现

  COM对象是给用户提供服务的封装的实体。这个应该和C++中类的对象理解起来是相似的。但是有时候也把COM对象当作提供服务的那个类。COM对象也对数据进行了封装,然后也提供了接口。不过和类还是有一些不一样的。类中的数据可以申明为public,然后让用户能够直接访问这些数据成员。但是用户不能对COM对象的数据进行直接访问,只能通过接口(如果有提供这种接口的话)来对数据进行间接的访问。一般COM接口指的是一组提供服务的接口,刚开始看这个定义很不习惯。因为C++中根本没有接口的概念,但是像Java这些语言就有接口的概念。关于COM接口可以按照Java的接口来理解(多懂几门语言真心是好事啊)。C++中的定义方式一般是用抽象类来实现,其中所有的函数全都是纯需函数,全部交给子类来实现。如某个接口的定义如下:

  

1 struct ICalc
2 {
3     virtual long __stdcall add(long a, long b) = 0;
4     virtual long __stdcall minus(long a, long b) = 0;
5     virtual long __stdcall times(long a, long b) = 0;
6     virtual long __stdcall devide(long a, long b) = 0;
7 };

  客户使用COM组件的时候,是不知道COM组件的确切对象的。所以COM组件需要注册注册表。但是客户还是需要一点什么标识来访问COM组件,使用COM对象,第一个直接的想法就是取个名字。但是会出现这种情况,A公司做个插件叫做Calculator,B公司做个插件也可以叫做Calculator,甚至家里的旺财写个插件都可以叫做Calculator。所以这个方法不是很好。为了解决这个重复的问题。微软决定使用GUID来对插件进行标识。GUID全称是Globally Unique Identifier,是一个128位的随机数。大家都随机,不怕随到一样的数吗?恩,确实有那个可能,但是这个概率太低了。理论上,如果一台计算机每秒产生10 000 000个GUID,则可以保证3240年不重复(当然是概率意义上,怎么算的了,我也不清楚啦)。反正GUID重复的概率是非常低的,可以放心使用。每个COM对象都有一个GUID来进行标识,这个GUID一般叫做CLSID。每一个COM接口也有一个GUID来进行标识,这个GUID一般叫做IID。在C++中,GUID定义如下:

1 typedef struct _GUID
2 {
3     DWORD Data1;
4     WORD  Data2;
5     WORD  Data3;
6     BYTE  Data4[8];
7 } GUID;

  按照COM规范,只要用户获得了一个COM对象的接口,那么用户可以通过它获取到该COM对象的其他接口(如果有的话)。一个用户在使用COM对象以前,用户需要建立COM对象(我觉得COM对象这个叫法真心的很讨厌,书上说COM对象既指那个提供服务的类,也指根据这个类实例化的对象)。建立COM对象当然是要分配一些资源的,在用完这些资源以后当然也是需要释放的,所以每一个COM对象都有一个计数。计数值为0的时候,那么对象就销毁这个COM对象。当有另外一个指针获得这个COM对象的话,那么计数就会增加一个,有一个指针释放了对这个COM对象的控制了,那么计数就减一。这种计数的方式类似于智能指针。但是COM对象的计数也没有智能指针那么智能,有时还是需要手动来释放的,所以用户承担着释放资源的重任。基于以上的说法,我们就需要一个获取其他所有接口的接口,增加计数的接口和减少计数的接口。COM提供的IUnknown接口已经提供了这三个接口(注意:COM接口一般指的是一组接口,而不是一个接口)。实际上所有的COM接口都必须从IUnknown继承而来。IUnknown提供了QueryInterface、AddRef和Release这三个接口。按C++的定义如下,但是实际定义的写法比较麻烦,这里只是比较简单的写法。

1 class IUnknown
2 {
3 public:
4     virtual HRESULT __stdcall QueryInterface(const IID &iid, void **ppv) =0;
5     virtual ULONG __stdcall AddRef() =0;
6     virtual ULONG __stdcall Release() = 0;
7 }

IUnknown是一个接口当然也有一个IID,IUnknown的IID为IID_IUnknown=00000000-0000-0000-C000-000000000046。然后剩下就是用户自己定义接口了。用户也可以定义多个接口。最后提供服务的类集成这些接口就组成了一个能够被用来创建COM对象的类了。比如下面的ICalc是一个接口,CCalc就是一个实现服务的类。

 1 class ICalc : public IUnknown
 2 {
 3 public:
 4     virtual long __stdcall add(long a, long b) = 0;
 5     virtual long __stdcall minus(long a, long b) = 0;
 6     virtual long __stdcall times(long a, long b) = 0;
 7     virtual long __stdcall devide(long a, long b) = 0;
 8 };
 9
10 class CCalc : public ICalc
11 {
12 public:
13     CCalc();
14     ~CCalc() = default;
15
16 public:
17     //IUnknown interface:
18     virtual HRESULT __stdcall QueryInterface(const IID &iid, void **ppv) override;
19     virtual ULONG __stdcall AddRef() override;
20     virtual ULONG __stdcall Release() override;
21
22     //ICalc interface:
23     virtual long __stdcall add(long a, long b) override;
24     virtual long __stdcall minus(long a, long b) override;
25     virtual long __stdcall times(long a, long b) override;
26     virtual long __stdcall devide(long a, long b) override;
27
28 private:
29     long m_lRef;
30 };

其中override是C++11标准所提供的关键字。
  这一篇博客就先写到这吧,后面还有需要继续写的,但是现在要回寝室了,后续的明天或者后天继续写。

PS:博主也是一个菜鸟,最近才开始写技术博客,如果各位发现了什么错误,欢迎拍砖,指出错误。

时间: 2024-12-13 07:22:56

《COM原理与应用》学习笔记二——COM对象和COM接口的实现的相关文章

马哥学习笔记二十二——高可用集群原理

HA Resource:资源 FailOver:故障转移 FailBack:故障转回 资源粘性:资源是否倾向于留在当前节点 Messaging Layer:集群服务信息层,基于UDP互相传递心跳信息,集群事务信息等 heartbeat(v1,v2,v3) heartbeat v3:heartbeat,pacemaker,cluster-glue corosync cman keepalived ultramonkey CRM:(cluster resource manager)集群资源管理器,统

Android学习笔记二

17. 在ContentProvider中定义的getType()方法是定义URI的内容类型. 18. SQLiteDatabase类中的insert/delete/update/query方法其实也挺好用的,我在EquipmentProvider类中做了实现 19. Android专门有个单元测试项目(Android Test Project),在这个项目中,可以新建一个继承AndroidTestCase类的具体测试类来单元测试某个功能.我新建了一个AndroidTestProject项目,在

【Unity 3D】学习笔记二十九:游戏实例——简单小地图制作

任何的学习,光看不练是学不好的.所以这次就总结回顾下怎么制作MMROPG类游戏中的小地图.在MMROPG类游戏里,主角在游戏世界里走动时,一般在屏幕右上角都会有一个区域来显示当前游戏场景的小地图.主角在游戏世界里走动,小地图里代表着主角的小标记也会随之移动.那怎么实现咧? 首先需要确定两个贴图,第一个是右上角的小地图背景贴图,应该是从Y轴俯视向下截取主角所在的位置大地图.第二个就是主角的位置大贴图.在本例中,因为没有学习unity地图制作,所以地图用一个面对象代替,主角用立方体代替,使用GUI来

Python学习笔记<二>:列表、元组、字典

1 列表和元组 可以将列表和元组当成普通的"数组",它能保存任意数量任意类型的Python 对象.和数组一样,通过从0 开始的数字索引访问元素,但是列表和元组可以存储不同类型的对象. 列表和元组有几处重要的区别.列表元素用中括号( [ ])包裹,元素的个数及元素的值可以改变.元组元素用小括号(( ))包裹,不可以更改(尽管他们的内容可以).元组可以看成是只读的列表.通过切片运算( [ ] 和 [ : ] )可以得到子集,这一点与字符串的使用方法一样. 举例如下: >>>

Caliburn.Micro学习笔记(二)----Actions

Caliburn.Micro学习笔记(二)----Actions 上一篇已经简单说了一下引导类和简单的控件绑定 我的上一个例子里的button自动匹配到ViewModel事件你一定感觉很好玩吧 今天说一下它的Actions,看一下Caliburn.Micro给我们提供了多强大的支持 我们还是从做例子开始 demo的源码下载在文章的最后 例子1.无参数方法调用 点击button把textBox输入的文本弹出来 如果textbox里没有文本button不可点,看一下效果图 看一下前台代码 <Stac

2. 蛤蟆Python脚本学习笔记二基本命令畅玩

2. 蛤蟆Python脚本学习笔记二基本命令畅玩 本篇名言:"成功源于发现细节,没有细节就没有机遇,留心细节意味着创造机遇.一件司空见惯的小事或许就可能是打开机遇宝库的钥匙!" 下班回家,咱先来看下一些常用的基本命令. 欢迎转载,转载请标明出处:http://blog.csdn.net/notbaron/article/details/48092873 1.  数字和表达式 看下图1一就能说明很多问题: 加法,整除,浮点除,取模,幂乘方等.是不是很直接也很粗暴. 关于上限,蛤蟆不太清楚

小猪的数据结构学习笔记(二)

小猪的数据结构学习笔记(二) 线性表中的顺序表 本节引言: 在上个章节中,我们对数据结构与算法的相关概念进行了了解,知道数据结构的 逻辑结构与物理结构的区别,算法的特性以及设计要求;还学了如何去衡量一个算法 的好坏,以及时间复杂度的计算!在本节中我们将接触第一个数据结构--线性表; 而线性表有两种表现形式,分别是顺序表和链表;学好这一章很重要,是学习后面的基石; 这一节我们会重点学习下顺序表,在这里给大家一个忠告,学编程切忌眼高手低,看懂不代表自己 写得出来,给出的实现代码,自己要理解思路,自己

JavaScript--基于对象的脚本语言学习笔记(二)

第二部分:DOM编程 1.文档象模型(DOM)提供了访问结构化文档的一种方式,很多语言自己的DOM解析器. DOM解析器就是完成结构化文档和DOM树之间的转换关系. DOM解析器解析结构化文档:将磁盘上的结构化文档转换成内存中的DOM树 从DOM树输出结构化文档:将内存中的DOM树转换成磁盘上的结构化文档 2.DOM模型扩展了HTML元素,为几乎所有的HTML元素都新增了innerHTML属性,该属性代表该元素的"内容",即返回的某个元素的开始标签.结束标签之间的字符串内容(不包含其它

马哥学习笔记二十四——分布式复制快设备drbd

DRBD: 主从 primary: 可执行读.写操作 secondary: 文件系统不能挂载 DRBD: dual primay, 双主(基于集群文件系统的高可用集群) 磁盘调度器:合并读请求,合并写请求: Procotol:drbd数据同步协议 A: Async, 异步  数据发送到本机tcp/ip协议栈 B:semi sync, 半同步  数据发送到对方tcp/ip协议 C:sync, 同步  数据到达对方存储设备 DRBD Source: DRBD资源 资源名称:可以是除了空白字符外的任意