COM原理与应用_读书笔记

推荐的参考书籍:
Inside COM(COM技术内幕)
Inside OLE
COM原理及应用
Essential COM(COM本质论)

===============

OMG和Microsoft提出了CORBA和COM,CORBA用于UNIX,而COM用于Windows;
不仅定义了组件之间的交互标准,也提供了组件程序运行所需的环境
组件可以是DLL--进程内组件in-process component;也可以是EXE程序--进程外组件out-of-process component
COM对象不同于一般面向对象语言(如C++)中的对象,COM对象建立在二进制可执行代码级的基础上,而C++等语言的对象建立在源代码级基础上
对于学生和计算机软件科研人员来说,COM带给他们的不仅仅是一项技术,而且是一种软件结构的实现。
OLE的第一个版本OLE 1中,组件程序和客户程序之间进行通信并没有使用COM,而是使用一种被称为动态数据交换(DDE,Dynamic Data Exchange)的机制(缺点:效率低、稳定性不好)
1个COM组件包含多个COM对象,1个COM对象包含多个COM接口。但大多数COM组件只包含1个COM对象
COM标准的实现部分是COM库

===============

COM库一般不在应用程序层实现,而在操作系统层次上实现,因此一个操作系统只有一个COM库实现。
按照COM规范,客户程序通过COM库完成对象的创建工作。COM库通过系统注册表所提供的信息进行组件的创建工作
组件程序把它所实现的COM对象的信息及接口信息都保存到注册表中,这个步骤称为组件的注册;如果一个组件具有这种自注册能力,我们称该组件为可自注册的

===============

COM组件的注册信息:
COM使用的节点HKEY_CLASSES_ROOT,其下最主要的是CLSID子键
如果是进程内组件,则组件的CLSID子键下包含了InprocServer32子键,该子键的缺省值为组件程序的全路径文件名;
如果是进程外组件,则组件CLSID子键下包含了LocalServer32子键,该子键的缺省值为组件程序的全路进文件名
在Windows系统中,除了用CLSID可以唯一标识一个COM对象外,同时也可以用字符串对组件对象命名,利用名字话的字符串来查找对象,这样的名字信息称为PorgID(Program Identifier)

===============

CLSIDFromProgID和ProgIDFromCLSID函数用于CLSID和ProgID的转换
组件类别:如所有的自动化对象都支持IDispatch接口,则可以把他们归成一类"Automation Objects"
Windows提供了一个用于注册进程内组件的实用工具RegSvr32.exe
只要进程内组件提供了相应的入口函数DllRegisterServer和DllUnregisterServer,RegSvr32就可以完成注册或注销工作

===============

对于进程内组件可用如下语句完成注册:
RegSvr32 C:\MyComObject\MyComObj.dll
RegSvr32 /u C:\MyComObject\MyComObj.dll

对于EXE进程外组件,本身为可执行程序,而且它也不能提供入口函数供其他程序调用,因此,COM规范中规定,支持自注册的进程外组件必须支持两个命令行参数/RegServer和/UnregServer,以便完成注册或注销操作(命令行参数与大小写无关,而且/可以用-代替)

===============

3.3类厂
组件程序需要提供一个标准的入口函数DllGetObjectClass,用于提供本组件程序的组件信息
确切的讲,类厂应该称为"对象厂",因为类厂是COM对象的生产基地,COM库通过类厂创建COM对象
COM规定,每一个COM对象类应该有一个相应的类厂对象,如果一个组件程序实现了多个COM对象,则应有多个类厂。
因为类厂本身也是个COM对象,它被用于其他COM对象的创建过程,那么类厂对象本身又是有谁来创建的呢?答案是DllGetClassObject引出函数。DllGetClassObject函数并不是COM库的函数,而是由组件程序实现的引出函数。
COM库在接到对象创建的指令后,它要调用进程内组件的DllGetClassObject函数,有该函数创建类厂对象,并返回类厂对象的接口指针,COM库或者客户一旦有了类厂的接口指针,它们就可以通过类厂接口IClassFactory的成员函数CreateInstance创建相应的COM对象

===============

COM库与类厂的交互

在COM库中有三个API函数可用于对象的创建,CoGetClassObject CoCreateInstance CoCreateInstanceEx。通常状况下,客户程序调用其中之一完成对象的创建,并返回对象的出示接口指针
CoGetClassObject调用DllGetClassObject引出函数,由DllGetClassObject创建类厂,并返回类厂对象接口指针。
CoCreateInstance在内部也调用了CoGetClassObject,客户只要指定对象类的CLSID和带输出的接口指针及接口ID,就可以得到对象的接口指针,客户程序可以不与类厂打交道;但此方法无法创建远程机器上的对象。
CoCreateInstanceEx可以获取远程对象
从以上三个用于创建对象的函数来看,一般我们按照下面的原则进行选择:
1. 如果创建远程对象或者希望一次获取对象的多个接口指针,则选用CoCoCreateInstanceEx
2. 如果我们希望获取类厂对象或者调用类厂的某些成员函数,则选用CoGetClassObject
3. 在其他情况下,使用CoCreateInstance,这是我们最常用的方法
一般情况下,客户程序或者COM库只是在创建组件对象的时候才使用类厂对象的接口指针,创建完成后就把类厂对象丢弃掉,以后如果还要创建组件对象,可以再次获取类厂对象,所以,类厂对象并不被长久保存,只是在创建过程中被用到

因为锁计数对整个组件程序负责,所以如果一个组件程序实现了多个类厂,则所有的类厂可以共用一个锁计数器,不必分开使用多个计数器;而且为了可以在其他函数中访问到该计数器,通常把它设为全局变量
引入锁操作后,判断一个组件程序是否可以被写出内存就增加了一个条件,既要判断组件程序中是否还存在组件对象,还要判断组件程序的锁计数器是否为0

COM库
如果一个应用程序用到COM的特性,在进行函数调用之前,首先必须调用COM库的初始化函数:HRESULT CoInitialize(IMalloc* pMalloc)
COM库的版本也在不断更新,如果应用程序要依赖于特定COM库,则它需要调用CoBuildVersion函数进行版本验证
凡是调用CoInitialize函数返回S_OK的进程或程序模块一定要有对应的释放操作,终止COM所维护的资源:void CoUninitialize(void)


 

原文地址:https://www.cnblogs.com/andy65007/p/1296310.html