《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:博主也是一个菜鸟,最近才开始写技术博客,如果各位发现了什么错误,欢迎拍砖,指出错误。

转载于:https://www.cnblogs.com/DennisXie/p/3961648.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/407214.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

禁止ipc$默认共享的方法

以下四种方法可以参考一下: A、一种办法是把ipc$和默认共享都删除了。但重起后还会有。这就需要改注册表。 1,先把已有的删除 net share ipc$ /del net share admin$ /del net share c$ /del …………(有几个删几个) 2,禁止建立空…

NODE属性说明

注:文本节点、元素节点或者注释节点等都是Node类型的子类,它们继承自Node类,所以这里的node可以是任何一种节点类型 1.node.nodeType用来以数字值返回指定节点node的节点类型 2.node.nodeName用来返回指定节点的节点名称 如果节点是元素节点…

使用临时文件mkstemp和输出errno对应的错误描述信息strerror

/* <<高级Linux编程.pdf>> page24-25: temp_file.cmkstemp: 从一个文件名模板(结尾是&#xff1a;XXXXXX)生成临时文件名&#xff0c;创建这个临时文件&#xff0c;将模式设置为仅当前用户可以访问&#xff0c;并且以读写权限打开这个文件。mkstemp函数用其他字符替…

微信h5网页关闭分享以及关闭当前页面

关闭网页分享一些按钮 document.addEventListener("WeixinJSBridgeReady", function () {WeixinJSBridge.call(hideOptionMenu); });关闭网页 WeixinJSBridge.call(closeWindow);

Linux Shell脚本中点号和source命令

Linux中一个文件是根据其是否具有执行属性来判断他是否可以直接运行的。就像Windows下的exe一样。如果我们要执行某一个文件&#xff0c;可以先将其权限修改为可执行(必须是所有者或者root才能修改)。然后&#xff0c;通过用sh来执行该脚本或者./脚本名。 但有时候我们并不想修…

[转载]使用命名管道实现进程间通信

使用命名管道实现进程间通信 来源 : VChelp 4.5 进程间通信 在Win32下提供的进程间通信方式有以下几种&#xff1a; 剪贴板Clipboard&#xff1a;在16位时代常使用的方式&#xff0c;CWnd类中提供了支持。 COM/DCOM&#xff1a;通过COM系统的代理存根方式进行进程间数据交换&…

HTML DOM之标签操作方法

1.document.getElementById(id)方法可返回对拥有指定 ID 的第一个对象的引用 2.document.getElementsByName(name)方法可返回带有指定名称的对象的集合 3.document.getElementsByTagName(tagname)方法可返回带有指定标签名的对象的集合。如果把特殊字符串 “*” 传递给 getEle…

Vue中动态(import 、require)显示img图片

vue中&#xff0c;经常会遇到显示图片的问题&#xff0c; 如果是一个普通组件的话&#xff0c;那么这样就可以了 <img src"../assets/images/avtor.jpg" width"100%"> 上文的弊端有两个&#xff1a; 首先&#xff0c;是采用绝对路径引入。如果以…

案例精解企业级网络构建

早就听说51CTO博客出书了,但由于放假在家,没有来得及购买.现在开学了,天天上51CTO网站,博客出书的广告打的到处都是,嘿嘿!~~想不关注都不行啊!看了各位博友对这本书的好评,终于禁不住诱惑,也在网上购买了一本.今天终于收到书了.打开包装,书真的很精美.自己非常喜欢,我是一名专科…

Oracle 中 for update 和 for update nowait 的区别

原文出处http://bijian1013.iteye.com/blog/1895412 一.for update 和 for update nowait 的区别 首先一点&#xff0c;如果只是select 的话&#xff0c;Oracle是不会加任何锁的&#xff0c;也就是Oracle对 select 读到的数据不会有任何限制&#xff0c;虽然这时候有可能另外一…

HTML DOM之节点操作方法(1)

1.checkboxObject.focus()方法用于为 checkbox 赋予焦点 2.checkboxObject.blur()方法用于让 checkbox 失去焦点 3.appendChild()在子节点列表之后插入新增的子节点 注&#xff1a;您也可以使用 appendChild()方法将一个元素移动到另一个元素中 这里就将”myList2”中最后一个…

常用端口号

端口号标识了一个主机上进行通信的不同的应用程序。 1.HTTP协议代理服务器常用端口号&#xff1a;80/8080/3128/8081/90982.SOCKS代理协议服务器常用端口号&#xff1a;10803.FTP&#xff08;文件传输&#xff09;协议代理服务器常用端口号&#xff1a;214.Telnet&#xff08;…

关于停止发表“每周新闻回顾”的通知

各位朋友&#xff1a;从2007年春节之后&#xff0c;老杨就基本上坚持每周整理当周重大IT新闻&#xff0c;如此坚持了一年。之后&#xff0c;由51CTO编辑部各位编辑轮流进行这项工作&#xff0c;算来已经超过一年半了。承蒙各位读者厚爱&#xff0c;如今新闻回顾已经成为51CTO.c…

单词统计程序

一个简单的单词统计程序&#xff0c; 问题来源: http://topic.csdn.net/u/20111114/10/2e439bbf-04c5-4042-9905-ece0bf008b97.html /* 功能&#xff1a;实现单词统计功能 */#include <stdio.h> #include <string.h>main() {char *t[20]; // 声明一个指针数组&a…

利用jQuery实现的Ajax 验证用户名是否存在

异步刷新实现方式有多种&#xff0c;也可以借助JS的多种框架&#xff0c;下面是使用jQuery框架实现的AJAX 验证用户名是否存在 jQuery.ajax概述 HTTP 请求加载远程数据。 通过jQuery 底层 AJAX 实现。简单易用的高层实现见 $.get, $.post 等。$.ajax() 返回其创建的 XMLHttpReq…

HTML DOM之节点操作方法(2)

9.document.hasFocus()方法返回布尔值&#xff0c;用于检测文档(或文档内的任一元素)是否获取焦点。没有参数 10.node.hasChildNodes()方法返回 true&#xff0c;如果指定节点拥有子节点&#xff0c;否则返回 false。没有参数 11.node.isDefaultNamespace(namespaceURI)方法返回…

git clone、git pull和git fetch的用法及区别

1.git clone git clone顾名思义就是将其他仓库克隆到本地&#xff0c;包括被clone仓库的版本变化。举个例子&#xff0c;你当前目录比方说是在e:/course/中&#xff0c;此时若想下载远程仓库&#xff0c;本地无需git init,直接git clone url&#xff08;url是你远程仓库的地址…