COM进程内组件与进程外组件
1. COM进程内组件
进程内组件以动态链接库的形式存在(后缀名为dll),客户端需要使用进程内组件提供的服务时只需要将dll加载进客户端进程。进程内组件必须提供自注册功能,这样客户端进程才能在需要的从注册表中查找到相应的信息,并加载该组件。
进程内组件需要导出四个函数
DllRegisterServer:
参数:无
返回值:HRESULT 指示注册操作的错误类型
DllUnregisterServer
参数:无
返回值:HRESULT 指示删除注册表中的相应项操作的错误类型
DllGetClassObject
参数1:CLSID&组件的CLSID(因为一个dll可以作为多个组件的载体)
参数2:IID&,要从组件中获取的接口IID
参数3:void**,接收获得的接口指针的双重指针
返回值: HRESULT 指示操作结果的错误类型,一般有(E_OUTOFME\
MORY, S_OK,E_NOINTERFACE,CLASS_E_CLASSNOTAVAILABLE);
DllCanUnloadNow
参数:无
返回值:HRESULT 指示是否可卸载该组件
说明:COM库每隔一段时间便会自动调用该方法判断是否可以卸载该组件。
进程内组件注册表中需要的内容
位于HKEY_CLASSES_ROOT的CLSID项下
其中7F21137D…为组件的CLSID
InprocServer32所对应的值为进程内组件的完整路径
ProgID 所对应的值为组件的易记名称客户端可以通过该名称获得组件的CLSID.
2.COM进程外组件
2.1 LPC和RPC
COM采用LPC(本地过程调用)和RPC(远程过程调用)的方法进行进程之间的通信,LPC用于在同一机器上的不同进程之间进行通信,而RPC用于在不同机器上的进程之间进行通信。
2.2 存根代理dll
为了提供LPC的处理,com提供了一个非常简便的方法,当组件为进程外组件时,客户将同一个模仿组件的dll进行通信,这个dll可以为客户完成参数调整以及LPC调用,这个dll在客户端称之为代理dll,而在服务器端称作为存根dll。
代理存根dll的生成步骤:
1. 编写idl文件
该idl文件包含了所有服务端组件定义的接口,组件标示符CLSID除外
2. 使用MIDL编译该IDL文件
编译后生成的一下几个文件
1) XXX_h.h 包含接口定义的头文件,和所有接口IID的声明
2) XXX_i.c 接口IID的定义
3) XXX_p.c 代理文件
4) Dlldata.c 数据文件
3. 使用以上文件生成存根代理dll
1) 在预处理增加REGISTER_PROXY_DLL
2) 提供输入库rpcrt4.lib uuid.lib
3) 添加def文件,导出下图五个函数
4) 编译生成dll
生成后的dll会有五个导出函数如下图
前面四个和进程内组件意义一致
2.3 进程外组件的注册
进程外组件注册需要注册存根代理dll和组件exe文件,其中存根代理dll的注册和进程内组件的注册一致,而exe文件的注册就依靠其命令参数来进行。
组件程序的两个用于注册的入口函数为DllRegisterServer和DllUnregisterServer,注册组件使用命令:RegSvr32 *.dll;反注册组件使用命令:RegSvr32 /u *.dll,进程内组件注册使用此命令。进程外组件注册必须支持两个命令行参数/RegServer和/UnregServer。
CLSID子键下:
图1
图2
Interface子键下:
图3
图4
其中ProxyStubClsid32为该接口的存根代理dll的CLSID,图1,这样在查询某接口时com库就知道到哪加载存根代理dll了
3 类厂
COM库通过类厂创建COM对象,对应每一个COM类,都有一个类厂专门用于该COM类的对象创建工作。类厂本身也是一个COM对象,它支持接口IClassFactory。
CreateInstance创建对应的COM对象,LockServer控制组件的生存周期。
类厂由函数DllGetClassObject创建。
DllGetClassObject返回类厂对象的接口指针,再通过CreateInstance创建对应的COM对象。
4.COM库与类厂的交互
创建对象函数:
1)若创建远程对象或希望一次获取对象的多个接口指针,选用CoCreateInstanceEx。
2)若希望获取类厂对象或要调用类厂的某些成员函数,选用CoGetClassObject,通常IID=IID_IclassFactory,进程内组件直接调用DLL的CoGetClassObject,若CoGetClassObject创建的类厂对象位于进程外组件,函数启动组件进程,然后等待,直到组件进程把它支持的COM类对象的类厂注册到COM中,返回类厂信息。
3)其他情况下,选用CoCreateInstance创建对象,CoCreateInstance封装类厂创建对象的过程,返回COM对象的接口指针,不能创建远程机器上的对象。
COM库初始化函数:CoInitialize
COM库终止函数:CoUninitialize
COM库内存管理:
COM提供的内存管理器标准,是一个COM接口IMalloc。当组件内存的分配和释放不在同一模块,需要用到内存管理器,COM库封装了三个API函数,用于内存分配和释放
CoTaskMemAlloc
CoTaskMemFree
CoTaskMemRealloc