COM(3)

3.1 进程内组件和进程外组件
3.1.1 进程内组件
3.1.2 进程外组件
3.2 通过注册表管理COM对象
3.2.1 注册表结构
3.2.2 COM组件注册信息
3.2.3 COM组件的注册操作
3.3 类厂
3.3.1 类厂和DllGetClassObject函数
3.3.2 COM库与类厂的交互
3.3.3 类厂的实现
3.3.4 类厂对组件生存期的控制
3.4 COM库
3.4.1 COM库的初始化
3.4.2 COM库的内存管理
3.4.3 组件程序的装载和卸载
3.4.4 常用函数和HRESULT
3.5 COM实现过程
3.5.1 进程内组件与客户的协作过程
3.5.2 进程外组件与客户的协作过程
3.6 字典组件例子程序的实现
3.6.1 字典组件类厂的实现
3.6.2 字典对象的实现






组件程序把它所实现的COM对象的信息以及接口信息都保存在注册表中,这个步骤称为组件的注册,如果组件程序具有这种自注册能力,则我们称该组件程序为可自注册的组件;客户程序在创建组件对象时,也需要直接或间接地访问注册表中的信息。通常,组件对象的创建工作由COM库来完成,COM库所进行的很多操作都依赖系统注册表提供的信息才能完成。


在Windows系统中,除了用CLSID可以唯一标识一个COM对象外,同时也可以用字符串对组件对象命名,利用名字化的字符串来查找对象,这样的名字信息称为ProgID。


COM提供了在注册表中对COM组件进行分类的机制,分类的原理很简单,如果COM组件支持同样一组接口,则可以把它们分到同一类中,一个组件对象可以被分到多个类中。比如所有的自动化对象都支持IDispatch接口,则可以把它们归成一类“Automation Objects”。类别信息也用一个GUID来描述,称为CATID。


Microsoft Visual C++ 提供了OleView.exe实用工具,会列出当前机器上的所有类别信息,以及每一种类别下的组件对象列表。


组件的注册:
1. 进程内组件的注册。用到了regsvr32.exe。
2. 进程外组件的注册。COM规范中规定,支持自注册的进程外组件必须支持两个命令行参数 /RegServer 和 /UnregServer,以便完成注册或注销有操作。


客户程序并不直接调用组件程序的引出函数,它调用COM库的函数进行组件对象的创建工作,COM库的创建函数根据注册表的信息并调用组件程序的入口函数来创建组件对象。组件程序需要提供一个标准的入口函数DllGetObjectClass,用于提供本组件程序的组件信息。


类厂应该称为“对象厂”,因为类厂是COM对象的生产基地,COM库通过类厂创建COM对象;对应每一个COM类,有一个类厂专门用于该COM类的对象创建操作。类厂本身也是一个COM对象,它支持一个特殊的接口:IClassFactory,其定义如下:
class IClassFactory: public IUnknown
{
virtual HRESULT __stdcall CreateInstance(IUnknown * pUnknownOuter, const IID& iid, void ** ppv) = 0;
virtual HRESULT __stdcall LockServer(BOOL block) = 0;
}


类厂本身也是个COM对象,它被用于其他COM对象的创建过程,那么类厂对象又由谁来创建呢?答案是DllGetClassObject引出函数。DllGetClassObject函数并不是COM库的函数,而是由组件程序实现的引出函数,原型:
HRESULT DllGetClassObject(
const CLSID& clsid,
const IID& iid,
(void **)ppv
);


CoGetClassObject, CoCreateInstance, CoCreateInstanceEx一般用于获取类厂。


COM库的使用:
HRESULT CoInitialize(IMalloc *pMalloc);
void CoUninitialize(void);


class IMalloc: public IUnknown
{
void * Alloc(ULONG cb) = 0;
void * Realloc(void *pv, ULONG cb) = 0;
void Free(void *pv) = 0;
ULONG GetSize(void *pv) = 0;
int DidAlloc(void *pv) = 0;
void HeapMinimize() = 0;
}
COM库提供了两种操作方法来进行内存分配或释放:
1. HRESULT CoGetMalloc(DWORD dwMemContext, IMalloc **ppMalloc);然后通过IMalloc进行内存的操作。
2. COM库封装了三个API函数。
void* CoTaskMemAlloc(ULONG cb);
void CoTaskMemFree(void *pv);
void CoTaskMemRealloc(void *pv, ULONG cb);


进程内组件的装载
客户程序调用COM库的CoCreateInstance或者CoGetClassObject函数创建COM对象,在CoGetClassObject函数中,COM库根据系统注册表中的信息,找到类标识符CLSID对应的组件程序(DLL文件)的全路径,然后调用LoadLibrary函数(实际上是CoLoadLibrary函数),并调用组件程序中的DllGetClassObject引出函数,DllGetClassObject函数创建相应的类厂对象,并返回类厂对象的IClassFactory接口,至此CoGetClassObject函数的任务完成。然后客户程序或者CoCreateInstance函数继续调用类厂对象的CreateInstance成员函数,由它负责COM对象的创建工作。
进程外组件的装载
进程外组件的装载过程与进程内组件的装载有所不同,但对于客户程序来说,并没有什么区别。在COM库的CoGetClassObject函数中,当它发现组件程序是EXE文件(由注册表组件对象信息中的LocalServer或LocalServer32值指定)时,COM库创建一个进程启动组件程序,并带上“/Embedding”命令行参数,然后等待组件程序;而组件程序在启动后,当它检查到“/Embedding”命令行参数后,就会创建类厂对象,然后调用CoRegisterClassObject函数把类厂对象注册到COM中,当COM库检测到组件对象的类厂之后,CoGetClassObject函数就把类厂对象返回。由于类厂与客户程序运行在不同的进程中,所以客户程序得到的是类厂对象的代理对象。一旦客户程序或COM库得到了类厂对象,它就可以通过类厂对象完成组件对象的创建工作。
从这个过程可以看出,进程内对象和进程外对象的不同创建过程仅仅影响了CoGetClassObject函数的实现过程,对于客户程序来说完全是透明的,所以,在客户程序中,可以把所有的COM对象都按照进程内对象来处理和理解,这使得COM应用的编程更为简单。


我们应该使用SUCCEEDED和FAILED宏来对HRESULT类型的结果值作出成功或失败的判断。







































评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值