COM:
COM组件是以WIN32动态链接库(DLL)或可执行文件(EXE)形式发布的可执行代码组成。
COM组件是遵循COM规范编写的
COM组件是一些小的二进制可执行文件
COM组件可以给应用程序、操作系统以及其他组件提供服务
自定义的COM组件可以在运行时刻同其他组件连接起来构成某个应用程序
COM组件可以动态的插入或卸出应用
COM组件必须是动态链接的
COM组件必须隐藏(封装)其内部实现细节
COM组件必须将其实现的语言隐藏
COM组件必须以二进制的形式发布
COM组件必须可以在不妨碍已有用户的情况下被升级
COM组件可以透明的在网络上被重新分配位置
COM组件按照一种标准的方式来宣布它们的存在
接口:
接口就是提供两个不同对象间的一种连接。
计算机程序是通过一组函数而进行连接的,这组函数就是定义了程序中不同部分的接口。
DLL的接口就是它所输出的那些函数。
C++类的接口就是该类的成员函数集。
COM中的接口是一组由组件实现的提供给客户使用的函数。
在COM中接口是一个包含函数指针数组的内存结构,数组元素是一个由组件实现的函数地址。
IUnKnown:
IUnKnown是一个接口。
所有COM接口都继承IUnKnown。
IUnKnown的定义在WIN32 SDK中的UNKNWN头文件中。
///IUnKnown的定义
interface IUnKnown
{
virtual HRESULT __stdcall QueryInterface(const IID& iid,void **ppv)=0;
virtual ULONG __stdcall AddRef()=0;
virtual ULONG __stdcall Release()=0;
}
IID:
它是一个结构,接口标识符结构。
IID标识了客户所需的接口。
每一个接口都有一个唯一的接口标识符。所以某个与IID相对应的接口绝对不会发生变化。
接口IID决定了COM组件的版本。
不同的接口具有不同的ID,包括不同版本的接口。
类厂:
类厂就是用来创建组件的组件。
类厂唯一的功能就是创建其他组件。
实际CoCreateInstance创建的不是COM组件,而是创建了类厂。
特定的类厂将创建特定的CLSID相对应的组件。
客户可以通过类厂支持的接口来对类厂创建组件的过程加以控制。
创建组件的标准接口是IClassFactory.
利用CoCreateInstance创建的组件实际上是通过IClassFactory.接口创建的。
用COM库提供的CoGetClassObject函数获得类厂的接口指针。
CoGetClassObject函数可以接收一个CLSID作为参数并返回相应类厂中某个接口指针。
CoGetClassObject函数的声明如下:
HRESULT __stdcall CoGetClassObject(
const CLSID& clsid, ///待创建组件的CLSID
DWORD dwClsContext, ///限定所创建组件的执行环境
COSERVERINFO * pServerInfo ///DCOM用来控制远程组件的
const IID& iid, ///组件上待使用接口的IID
void ** ppv ///返回指向所需组件的类厂的指针,通常是IClassFactory
);
CoGetClassObject需要DLL中的一个特定函数来创建类厂, 这个函数是DllGetClassObject。
客户通过调用CoGetClassObject来启动组件的创建过程。
COM库实现CoGetClassObject函数。
CoGetClassObject调用DLL的DllGetClassObject函数。
DllGetClassObject函数创建类厂。
类厂的创建方式由开发人员决定。
类厂被创建后返回IClassFactory接口。
通过此接口开发人员便可以控制创建组件了。
IClassFactory
类厂所支持的用于创建组件的标准接口。
大多数组件均可用这个接口来创建。
IClassFactory有两个成员函数,一个是CreateInstance一个是LockServer。
包容和聚合
包容和聚合可以使我们对组件进行改造。
包容和聚合是一个组件使用另一个组件的技术。
被调用的组件被称为内部组件,调用它的组件被称为外部组件。
包容就是外部组件包含内部组件的接口,外部组件仅仅是内部组件的客户,它将使用内部组件的接口来实现它的接口。
聚合就是外部组件聚合内部组件的接口,外部组件直接把内部组件的接口返回给客户。
对聚合的每一个接口,可能会包容成百上千的其他接口。
聚合和包容可以混合起来使用。
盲聚合
外部组件聚合了内部组件实现的多个接口。
外部组件放弃了它对暴露给客户的内部组件接口的控制权。
建议尽量不使用盲聚合。
智能接口指针
智能接口指针是用来封装接口指针的。
智能指针实际上就是一个重载了操作符->的类。
智能指针包含指向另外一个对象的指针。
智能接口指针包含的指针指向一个接口。
可以通过一个接口类型指向其IID的指针来创建接口指针。
然后调用CoCreateInstance来创建所需的组件并获得其指针。
当程序执行离开智能指针的作用域时,它将在它的析构函数中自动调用Release。
当产生了异常情况时,相应的接口可以被释放,因为智能指针是一个C++对象。
大多数智能指针实现了Release函数,可以用点记法来调用。
可以用指定一个NULL值来释放智能指针对应的接口。
通过重载=操作符,可以将一个接口指针赋值给智能指针包含的指针。
包装类
对于某些接口,封装接口本身比使用智能指针更好。
一个包装类是一个或多个COM接口的客户,它所提供的是对这些接口用法的抽象。
应用程序可以调用包装类的成员函数,由这些成员函数调用COM接口中的成员函数。
包装类可以充分利用C++的一些特性,如函数名重载、操作符重载、默认参数等。
包装类必须实现它所包装的接口的所有成员。
包装类可以在调用接口成员函数的前后加上新的代码。
包装类可以将几个单独的接口组合成一个逻辑单位。
MFC OLE支持基本上就是一种功能强大的包装类。
接口基类
实现IUnknown的基类。
基类Cunknown实现一个非委托unknown接口。
宏DECLARE_IUNKNOWN实现一个委托unknown接口。
对于从Cunknown继承的组件,当它没有被聚合时,GetOuterUnknown返回的是组件的INon -delegationUnknown接口指针;当它被聚合时,返回的则是外部组件的IUnknown接口指针。
Cunknown的构造函数接收指向外部unknown接口的指针作为参数,并将其保存供GetOuter -Unknown函数使用。
Cunknown::Init虚函数用来创建被包容或聚合的组件。
Cunknown::FinalRelease虚函数用来给被删除的组件提供一个释放它所保持的指向内部组件接口指针的机会。
类厂基类
CFactory实现IClassFactory接口。
CFactory实现DLL的入口点(如DllGetClassObject)的代码。
CFactory允许同一个DLL包含不同的组件,并且这些组件共享一个IClassFactory实现。
CFactory可以满足下述三个要求的任意组件:
组件必须实现一个具有如下原型的创建函数。
HRESULT CreateFunction(IUnknown * pUnknownOuter ///如此参数非空,则组件是被聚合的。
Cunknown ** ppNewComponent)
组件必须是从Cunknown继承得到的。
组件必须添充一个CFactoryData结构并将其加入到全局数组g_FactoryDataArray中。
CFactoryData包含5个成员变量:组件的类标识符、指向组件创建函数的指针、保存在windows注册表中的一个友好名称、ProID以及一个与版本无关的ProID、一个用于查找CLSID的辅助函数。
CFactory根据g_FactoryDataArray来决定它能创建哪些组件。