当前位置:C++技术网 > 资讯 > COM组件学习笔记1

COM组件学习笔记1

更新时间:2015-11-14 22:00:23浏览次数:1+次

COM规范中,并没有对COM对象进行严格的定义,但COM提供的是面向对象的组建模型,COM组建提供给客户的是以对象形式封装起来的实体。客户程序与COM组件程序进行交互的实体是COM对象,他并不关心组件模块的名称和位置(即位置透明性)。COM组建的位置对客户来说是透明的,因为客户并不直接访问COM组件。客户程序通过一个全局标识符进行对象的创建和初始化工作。为此,COM规范采用了128位全局唯一标识符GUID,这是一个随机数。

在C/C++语言中可以用这样的结构来描述:


typedef struct .GUID
{
    DWORD Data1;
    WORD    Data2;
    WORD    Data3;
    WORD    Data4[8];
}GUID;
COM库为我们提供了以下的API函数可以产生GUID:
HRESULT CoCreateGuid(GUID *pguid);
如果创建GUID成功,则函数返回S_OK,并且pguid将指向所得到的GUID值。实际上CLSID是用来的标识COM对象的GUID,因此CLSID在结构定义上与GUID一致。
从技术上讲,接口是包含了一组函数的数据结构,通过这组数据结构,客户代码可以调用组建对象的功能。
COM规范在采用OSF的DCE规范描述远程调用接口IDL的基础上,进行扩展形成COM接口的描述语言。
COM定义的每一个接口都必须从IUnknown继承过来,其原因在于IUnknown接口提供了两个非常重要的特性:生存期控制和接口查询。

首先我们看看IUnknown的定义:


interface IUnknown
{
    HRESULT    QueryInterface([in]REFIID iid,[out]void **ppv);
    ULONG       AddRef(void);
    ULONG       Release(void);
}
为了方便理解和对照,我们同时给出IUnknown的C++定义的形式:


class IUnknown
{
        public:
            virtual HRESULT _stdcall QueryInterface(const IID& iid,void **ppv)=0;
            virtual HRESULT _stdcall AddRef()=0;
            virtual HRESULT _stdcall Release()=0;
};
IUnknown包含了三个成员函数:QueryInterface,AddRef和Release。函数QueryInterface用于查询COM对象的其它接口指针,函数AddRef和Release用于对引用计数进行操作。
引用计数就是为了清除COM组件的对象。我就不详述了。我们看看QueryInterface。
按照COM规范,一个COM对象可以实现多个接口,客户程序可以在运行时刻对COM对象的接口进行访问。那么对象的多个接口之间是如何联系起来的呢?这就是IUnknown其中的成员函数所要解决的问题。
HRESULT    QueryInterface([in]REFIID iid,[out]void **ppv);
函数的输入参数iid为接口标识符IID,输出参数ppv为查询得到的结果接口指针,如果对象没有实现iid所标识的接口。则输出参数ppv指向空。
当客户创建了COM对象后,创建函数总会为我们返回一个接口指针,因为所有的接口都继承与IUnknown,所以所有的接口都有QueryInterface成员函数,于是。当我们得到初始的接口指针之后,我们就可通过它的
QueryInterface函数获得该对象所支持的任何一个接口指针。
下面的代码显示客户程序调用QueryInterface的用法:
IDictionary *pIDictionary = CreateObject(CLIST_Dictionary,IID_Dictionary);////创建对象
if(pIDictionary ==NULL)
    return;
BOOL retValue = pIDictionary->LoadLibrary("...");
if(retValue ==FALSE)
{
    pIDictionary->release();
    return ;
}
....
ISpellCheck *pISpellCheck;
HRESULT result=pIDictionary->QuaryInterface(IID_SpellCheck,(void **)&pISpellCheck);
 if(result!=S_OK)
{
    pIDictionary->Release();
    return ;
}
pIDictionary->Release();
pISpellCheck->Release();
................
COM中COM对象支持多个接口,则客户通过调用QueryInterface函数可以非常灵活的在接口指针之间来回跳转,而且不同的客户跳转的顺序也不见的一样,所以制定了一些规则以避免矛盾。在这里我就不详述了。
在C++语言中,实现多借口的COM对象有两种简便方法,我就讲一种。利用多继承,把所支持的接口作为其基类,然后在对象类中实现接口成员函数。


代码内存结构图:

查找函数实现代码:


QueryInterface函数对于iid的三种可能值分别进行了处理,不管客户要想查询字典对象所支持的那个接口,QueryInterface函数都会返回相应的接口指针。