文章目录
概述:
本章内容主要是COM对象的一些基本知识
本章把com对象称为对象 把com接口称为接口
2.1 com对象
客户端不需要知道com组件的安装位置 只需要知道和哪一个com组件进行通信
2.1.1 com对象的标识–CLSID
CLSID是通过网络适配器的地址和时间随机数生成的
极小概率重复 是一个128位的全局唯一标识符
有专业的工具去产生 这个GUID :UUIDGen.exe GUIDGen.exe
com库提供的Api可以产生GUID
- HRESULT CocreateGuid(GUID * pguid);
一个主要的概念GUID并不是专门来定义COM对象标识符的 也可以用于其他实体的标识符 比如后面的接口标识符
2.1.2 COM对象与C++对象的比较
1:封装特性
两者都有 形式不同 COM对象完全封装在对象内部 外部不可能对其内部进行访问 或者通过函数进行访问 也会对其设置的值进行有效性的判断
C++对象通过protect private public 三种属性来封装内部的属性 根据需要来对其属性进行访问
2: 可重用性
都有 但是表示形式不同
- com对象的表现形式 表现为包容和聚合 一个对象完全可以使用另外一个对象的功能
C++的可重用性表现在继承,派生类可以调用父类非私有成员函数 - com 对象使用其他对象的特性 是动态的 需要重新编译或者设置 C++的表现在源代码级别的重用性,通过C++语言的类来继承实现 当父类发生改变的时候 子类的文件必须要重新进行编译处理 重用性表现在代码的管理上面
- C++最广泛的是类聚 在发展的过程中 衍生出了很多类库 比如说MFC OWL 窗口类库
实际开发中都会使用到 源代码级别使用C++的可重用性 组件开发中使用COM组件的特性
2.2 COM接口
包括接口的表示 接口函数的调用习惯 参数的处理 接口和独享的卦象你 以及接口与C++的关系 COM接口所具备的特性
2.2.1 从API到COM接口
例如 字处理应用系统 需要查字典功能 查字段的功能就应该放在组件程序里面 。
如果以后字典的查找算法或者字典库发生变化 ,只要com接口不变,新的组件程序还是可以被应用系统使用
设计一组查字典的函数·
通过这些函数建立主程序和字典组件程序之间的联系 主程序可以直接通过com函数来进行相关函数的查找 这些com组件库的查找字典功能同时也可以提供给其他的程序来使用
这个组件很好把两个程序链接在一起 但是还是存在下面的问题
- api函数比较多的时候 不方便管理
- api函数需要标准话 以适应不同的变成语言
com组件定义了一套完整的接口规范,不仅可以弥补以上api作为组件接口的不足 还可以发挥组件对象的优势
2.2.2 接口定义和标识
客户端 通过指向接口数据结构的指针来调用接口成员函数
里面是包含是接口函数表的
所以无论上面语言 只要支持这样的内存结构描述 就可以定义接口‘
2.2.3 用c++语言定义接口
com接口的vtable 和 class的vtable的完全一致 (类的虚函数表)
由此可知 C++的虚函数表特性设计和COM的接口规范设计完全一致
如果用c语言来表示特性的话 则会相对麻烦一点
2.2.4 接口描述语言IDL
IDL用于定义com接口和常用的数据类型
有MVC++提供了MIDL工具 就可以将IDL接口描述变异成c/C++兼容的头文件格式 能被客户端程序使用
2.2.5 接口的内存模型
直接通过代码来演示 这部分和C++本身的特性十分相似
此时如果直接使用 那么内存模型如下
如果使用了两个字典类型的对象 那么使用的情况是下面的情况 注意一点 Cdirctionary这个对象的公共数据是下面的数据
注意这个模型就是两个实例使用 一个父类里面的数据
但是如果其中一个实例 它自己去实现了 这里父对象 CDictionary里面的部分虚函数 则
内存模型会变成下面这种形式
这个特性和C++中的十分相近
2.2.6 接口的一些特点
- 二进制特性 适配不同的语言
- 接口不变性 接口不发生改变
- 继承性
- 多态性
2.3 IUnKnown 接口
IUnKnown 引用计数来控制对象的生命周期
客户一般只会得到一个接口指针 如果需要其他指针 可以通过接口查询的方法来完成接口之间的跳转
三个常用的函数 QueryInterface AddRef 和 Release
2.3.1引用技术
2.3.4接口查询
QueryInterface 方法简介
QueryInterface 是 COM 中每个接口必须支持的函数,用于在对象的不同接口之间导航,确保对象可以以动态和灵活的方式提供服务。
方法签名
HRESULT QueryInterface(
REFIID riid, // 目标接口的 IID(接口标识符)
void** ppv // 接口指针的输出地址
);
参数说明
riid:
表示目标接口的唯一标识符(GUID),由接口定义时的 IID 表示。
例如,IID_IUnknown 表示查询 IUnknown 接口。
ppv:
返回目标接口指针的地址。
如果对象支持该接口,则返回对应接口的指针,并增加引用计数(AddRef 被隐式调用)。
如果对象不支持该接口,则返回 NULL。
返回值
S_OK:
成功查询到目标接口,ppv 指针有效。
E_NOINTERFACE:
目标接口不受支持。
其他错误代码表示查询过程中发生了其他异常。
2.3.5com 对象接口原则
以上特性 显示了COM组件的灵活性
2.3.6 QueryInterface 成员函数的实现
下面演示多重继承实现多个接口支持
可实现QueryInterface函数 结构如下
具体的代码实现
可以看到 默认给了一个Idirction的的接口指针 如果只传递 最基本的UUID 下面是根据具体的UUID来选择不同的接口指针 这里的代码很清晰
2.3.7 COM对象和接口图示法
如图 建议编写组件文档时候 采用这种表示方式 后续也采用这种表示方式