COM的全称是Component Object Model,是一种用来建立组件二进制和网络规范。COM组件是遵守COM规范的软件模块,可以是dll,也可以是exe。COM应用是基于C/S模型的,概括起来就是COM组件向COM客户端提供服务。从技术上讲,一个进程内的COM完全可以被认为就是一个普通的DLL—动态连接库!如果抛弃常用的COM API,CreateCOMObject()或者CreateOLEObject() ,那么您完全可以直接采用加载普通DLL的方式来调用这个COM组件,比如说,您可以直接用LoadLibrary()函数来加载这个DLL,然后使用 GetProcAddress来调用从这个DLL里输出的接口,从而完成各项操作。这是完全可行的。然而,把一个COM仅仅看成一个 DLL,那是非常肤浅的看法 – DLL仅仅是一种表现形式而已。更重要的是,COM实现了一种规则。
COM的几大优势:1、封装性,可以提高产品的安全性;2、可重用性,能实现跨语言平台的重用,VC可以用VB做的组件,虽然MS宣称可以跨OS,但现在并没有跨OS的组件应用;
COM组件通过接口提供服务,接口是COM的关键所在,接口描述语言是IDL。每个COM对象之少有一个接口。接口实际上是一组纯虚函数的集合。
全局唯一标识符GUID是全球范围内唯一的128位随机数,用于标志组件对象的GUID称为CLSID(Class identifier),用于标识接口的GUID称为IID(Interface identifier)。
IUnknown接口类是所有组件对象的类都要必须继承的, 他定义了三个方法QueryInterface,AddRef,Release。 IUnknown::QueryInterface(REFIID riid /*in*/, void** ppObect/*out*/)方法得到该组件的其他接口的指针 。 IUnknown::AddRef/Release负责管理该组件的生存期, 当有人使用该组件时,保证该组件不会被意外删除;没人使用该组件时,保证该组件被自动删除。
类厂标准化后,形成了抽象基类IClassFactory,它也是继承自IUknown接口,他的定义如下:
Class IClassFactory : public IUnknown
{
METHOD(CreateInstance)( IUnknown * pUnkOuter,
IID riid, void ** ppvObject) = 0;
METHOD(LockServer)(BOOL bLook) = 0;
};
在COM库中有三个函数可以创建对象(获得某个接口):CoGetClassObject ,CoCreateInstance,CoCreateInstanceEx。
CoGetClassObject 的函数原型是:
STDAPI CoGetClassObject(
REFCLSID rclsid, //rclsid:class-id,指定了COM类的唯一标识。
DWORD dwClsContext, //dwClsContext:可执行代码的运行上下文。
COSERVERINFO * pServerInfo, //pServerInfo:被用在DCOM中,一般设为NULL
REFIID riid, //riid: 通常情况下是接口IClassFactory的标识符IID_IClassFactor。
LPVOID * ppv //ppv:用来存放获得的接口指针
);
客户端调用CoCreateInstance创建类实例。CoCreateInstance查找注册表并加载DLL,调用DllGetClassObject。DllGetClassObject搜索DLLs的类工厂清单找出与类工厂匹配的类ID,然后将类厂对象接口通过参数ppv返回。
要实现一个进程内的COM,通常需要以下几步:
1. 建立一个DLL项目,并导出以下四个函数:
DllGetClassObject, DllCanUnloadNow, DllRegisterServer, DllUnregisterServer;
2. 定义自定义的接口,同时必须实现Iunknown接口。
3. 建立GUID,以标识这个组件以及自定义的接口。
4. 在注册表中注册以标记这个DLL。
原文: