Com原理及應用——Com對象和接口
1、COM对象的理解
COM对象类似于C++语言中类的概念,类的每个实例代表一个COM对象,它也包括属性(即状态)和方法(即操作),状态反映对象的存在,方法就是接口。
2、COM对象的标识-CLSID
GUID是一个128位的随机数,重复概率极低。它的值来源于两部分:空间值(网卡地址或随机数)和时间值。
获得GUID值可以使用VC++提供的工具:GUIDGen.exe 和 UUIDGen.exe。或者使用COM库的API函数CoCreatGuid()。
3、COM对象与C++对象的比较
COM对象将数据完全封装在对象的内部。C++对象的封装是在语义上的封装,通过不同的数据类型实现数据的封装。
COM对象的可重用性通过包容和聚合实现。C++对象的可重用性通过类的继承来实现。
COM对象的多态性通过其接口体现,C++对象的多态性通过其虚函数体现。
4、COM接口的作用和意义
COM规范的核心内容是关于接口的定义,虽然COM本身并不复杂,但是围绕COM接口有很多内容值得仔细探讨,包括接口的标识、接口函数的调用习惯、参数处理、接口与对象的关系以及接口与C/C++的关系、COM接口多具有的特性等。
COM定义了一套完整的接口规范,不仅可以弥补API作为组件接口的不足,还从分发挥了组件对象的优势,并实现了组件对象的多态性。
5、接口定义和标识
从技术上讲,接口是包含了一组函数的数据结构,通过这组数据结构,客户代码可以调用组件对象的功能。
客户程序用一个指向接口函数结构的指针来调用接口成员函数。实际上接口指针指向另一个指针pVtable。
接口函数表称为虚函数表(Virtual Function Table ,简称vtable),指向vtable的指针为pVtable。对于一个接口来说,它的虚函数表vtable是确定的。
6、接口设计的问题
在接口成员函数中,字符串变量必须用Unicode字符指针,这是COM规范的要求。
COM API函数使用大多数语言惯用的_stdcall调用习惯。
用C语言定义COM接口,需要有结构体struct定义其接口结构,接口成员函数必须有一个this指针。
用C++语言定义COM接口,因为由C++语言class的实现机理可以看出,COM接口结构中的vtable与class的vtable(类的虚函数表)完全一致,因此,用class描述COM接口是最方便的手段。此时,接口成员函数隐藏了this指针。
class 型接口的说明要比struct 型接口的说明简捷得多。
7、COM接口与对象的联系
接口类只是一种描述,并不提供具体的实现过程。如果COM对象要实现接口,则COM对象必须以某种方式把它自身与接口类联系起来,然后把接口类的指针暴露给客户程序,于是客户程序就可以调用对象的接口功能了。
用 class型接口通过把接口指针(this)与对象数据绑定在一起的方法实现对COM接口的支持比较直观、简捷易于理解。实际上,也可以采用其他的方法来实现接口,只要接口成员函数中this指针(即接口指针)与对象数据能建立确定的连接,在接口成员函数中可以访问到对象数据即可。例如,VC++的MFC 库和ATL(active template library ,活动模板库)模板库分别采用了不同的机制来提供对COM接口的支持。
8、接口描述语言IDL
COM 规范在采用OSF的DCE规范描述远程调用接口IDL(interface description language ,接口描述语言)的基础上,进行扩展形成了COM接口的描述语言。接口描述语言提供了一种不依赖于任何语言的接口描述方法,因此,它可以成为组件程序和客户程序之间的共同语言。
COM 规范使用的IDL接口描述语言不仅可用于定义COM接口,同时还定义了一些常用的数据类型,也可以描述自定义的数据结构,对于接口成员函数,我们可以制定每个参数的类型、输入输出特性,甚至支持可变长度的数组的描述。VC++提供了MIDL工具,可以把IDL接口描述文件编译成C/C++兼容的接口描述头文件(.h)。
9、接口的内存模型
COM对象往往有自己的属性数据,它们反映对象的状态,并用于区分不同的对象。对于有多个对象的客户,数据属性是不能公用的。
10、接口的特点
二进制特性
接口不变性
继承性(扩展性):类似于C++中类的继承性,接口也可以继承发展,但方式不同。类继承不仅是说明继承,也是实现继承,即派生类可以继承基类的函数实现,而接口继承只是说明继承,即派生的接口只继承了基接口的成员函数说明,而没有继承基接口的实现。类继承允许多重继承,但接口继承只允许单继承。根据COM规范,所有接口都必须从IUnknown派生,可以直接派生,也可以间接派生。但大多数都是直接派生。OLE系统中,接口最后字母是“2”或“Ex”的,标煤它是一个继承接口。
多态性:COM对象具有多态性,其通过COM接口体现。
11、IUnknown接口提供了两个非常重要的特性:生存期控制(使用引用计数)和接口查询。
12、IUnknown接口引用计数的设置层级
引用计数在组件一级实现则计数分辨率太粗(选择全局变量),在对象一级实现恰好(使用C++类的成员变量),在接口一级实现则计数分辨率太细(使用类成员变量)。
13、使用引用计数的规则
根据不同场合使用或者传递接口指针标量进行分类,并给出相应的规则:
(1)函数的参数中使用接口指针变量。
输入参数:由于输入参数由调用函数控制,因此被调用函数执行过程中,接口指针一定保持有效,引用计数不需要改变。
输出参数:输出参数是指在被调用函数执行过程中进行赋值的参数,而且被调用函数并没有用到函数初始化传进来的值,输出参数相当于函数的一个返回值。在C/C++语言中,输出参数为一个指针变量(COM中不使用引用变量)。因为输出参数相当于在被调用函数中生成了一个新的接口指针变量,因此,在被调用函数返回之前,对输出参数应该调用AddRef使接口引用计数增1。这条规则也适用于函数返回值为接口指针变量的情况。
输入-输出参数:在参数被修改之前,对原来传进来的接口指针调用Release以使引用计数减1,在参数被修改之后,对新的接口指针变量调用AddRef,以标记对新的接口指针的引用。如果在函数执行过程中参数没有被修改,则不需要改变。
(2)局部接口指针变量:因为在局部函数块中,接口指针总是有效的,所以,一个局部接口指针变量被赋了值并调用了接口成员函数,引用计数不需要改变。
(3)全局接口指针变量:把全局接口指针变量作为输入参数传给某个函数之前,应该调用AddRef以保证在函数调用中可以使用给接口指针变量,因为它是全局变量,其他的函数有可能会调用Release函数。在函数返回之后应该调用Release函数。
(4)C++中类成员变量为接口指针变量:因为对于类的作用域来讲,成员变量相当于全局变量,因此适用于规则(3)。
(5)当以上情形都不适合时,使用以下一般的规则:
在顺序执行过程中,如果要对一个接口指针变量赋值,则对赋值后的接口指针变量调用AddRef,并且,如果赋值前的接口指针变量还没有结束,则赋值前必须对它调用Release以便先结束它的使用。
如果要结束使用一个接口指针变量,以后不再用到它了,则调用Release函数。
14、接口查询
使用QueryInterface函数查询接口,其返回值有S_OK、E_NOINTERFACE、E_UNEXPECTED。
15、COM对象的接口原则
(1)对于同一个对象的不同接口指针,查询得到的IUnknown接口必须完全相同。即每个对象的IUnknown接口指针是唯一的。
(2)接口对称性。即对一个接口查询其自身总应该成功。
(3)接口自反性。
(4)接口传递性。
(5)接口查询时间无关性。
16、多接口COM对象的实现方法
在C++语言中有两种实现方法:一是使用多重继承,把所支持的接口作为其基类,然后在对象类中实现接口成员函数;二是使用内嵌接口类成员。
Com原理及應用——Com對象和接口的更多相关文章
- 【夯实Nginx基础】Nginx工作原理和优化、漏洞
本文地址 原文地址 本文提纲: 1. Nginx的模块与工作原理 2. Nginx的进程模型 3 . NginxFastCGI运行原理 3.1 什么是 FastCGI ...
- 玩转Windows服务系列——Debug、Release版本的注册和卸载,及其原理
Windows服务Debug版本 注册 Services.exe -regserver 卸载 Services.exe -unregserver Windows服务Release版本 注册 Servi ...
- EasyMock 使用方法与原理剖析
from:http://www.ibm.com/developerworks/cn/opensource/os-cn-easymock/ Mock 方法是单元测试中常见的一种技术,它的主要作用是模拟一 ...
- EasyMock 使用方法与原理剖析--转载
原文地址:http://www.ibm.com/developerworks/cn/opensource/os-cn-easymock/ Mock 方法是单元测试中常见的一种技术,它的主要作用是模拟一 ...
- 【转】Android LCD(二):LCD常用接口原理篇
关键词:android LCD TFT TTL(RGB) LVDS EDP MIPI TTL-LVDS TTL-EDP 平台信息:内核:linux2.6/linux3.0系统:android/ ...
- 玩转Windows服务系列——Debug、Release版本的注册和卸载,及其原理
原文:玩转Windows服务系列——Debug.Release版本的注册和卸载,及其原理 Windows服务Debug版本 注册 Services.exe -regserver 卸载 Services ...
- 开源纯C#工控网关+组态软件(四)上下位机通讯原理
一. 网关的功能:承上启下 最近有点忙,更新慢了.感谢园友们给予的支持,现在github上已经有.目标是最好的开源组态,看来又近一步^^ 之前有提到网关是物联网的关键环节,它的作用就是承上启下. ...
- Netty中ByteBuf的引用计数线程安全的实现原理
原文链接 Netty中ByteBuf的引用计数线程安全的实现原理 代码仓库地址 ByteBuf 实现了ReferenceCounted 接口,实现了引用计数接口,该接口的retain(int) 方法为 ...
- Spring Boot的Listener机制的用法和实现原理详解
之前在介绍了在spring-boot启动过程中调用runner的原理,今天我们介绍另外一种可以实现相似功能的机制:spring-boot的Listener机制. 通过注册Listener,可以实现对于 ...
随机推荐
- Google2016开发者大会
Android主讲: 一.吴晶:android笔记博主(博客:http://www.race604.com/) 主题:Android低功耗蓝牙(BLE)实践 低功耗蓝牙在可穿戴和智能家居里边用的比较多 ...
- ubuntu下安装Vmare Workstation,并安装mac补丁
最近想学习一下关于ios方面的开发,但是苦于自己的电脑已经装了两个系统:一个win7,一个ubuntu.两系统均装在物理硬盘上,不想格盘,所以装个虚拟机玩玩.决定使用Vmare Workstation ...
- [转]Java远程方法调用
Java远程方法调用,即Java RMI(Java Remote Method Invocation)是Java编程语言里,一种用于实现远程过程调用的应用程序编程接口.它使客户机上运行的程序可以调用远 ...
- 0.0C语言重点问题回顾
左值和右值得区别:左值是用来表明变量的身份的,右值更加侧重于值本身: void*是个例外,它只有基地址没有类型信息,所以无法解引用. int *p = malloc(100); char *s = m ...
- 04_RHEL7.1忘记root密码
在开机进入启动项时,选择需要重设密码的那个启动项 按e进入编辑模式,找到rhgb和quiet参数(几乎在最下面),替换为 init=/bin/sh 按ctrl+X不需密码进入shell 以rw的方式重 ...
- SQL SAVE TRANSACTION
--创建存储过程 create procedure qiantaoProc @asd nchar(10) as begin begin try begin transaction innerTrans ...
- Python自动化运维之20、HTML
一.HTML相关概念 HTML是英文Hyper Text Mark-up Language(超文本标记语言)的缩写,他是一种制作万维网页面标准语言(标记).相当于定义统一的一套规则,大家都来遵守他,这 ...
- ubuntu下MySQL安装配置及基本操作
在linux下安装方法: 分为四种:一: 直接用软件仓库自动安装(如:ubuntu下,sudo apt-get install mysql-server; Debain下用yum安装): 二:官网下载 ...
- 转:聊聊并发(八)——Fork/Join框架介绍
1. 什么是Fork/Join框架 Fork/Join框架是Java7提供了的一个用于并行执行任务的框架, 是一个把大任务分割成若干个小任务,最终汇总每个小任务结果后得到大任务结果的框架. 我们再通过 ...
- poj 2406Power Strings
http://poj.org/problem?id=2406 #include<cstdio> #include<cstring> #include<algorithm& ...