COM学习笔记(二)

COM对象的标识——CLSID

  客户程序不直接去访问COM组件,而是通过一个GUID进行对象的创建和初始化工作。COM规范采用了128位全局唯一标识符GUID。一个GUID的例子如下:

{54BF6567-1007-11D1-B0AA-444553540000}

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

typedef struct _GUID
{
  DWORD Data1;
  WORD Data2;
  WORD Data3;
  BYTE Data4[8];
}GUID;

  于是前面的GUID例子可以定义为:

extern “C” const GUID CLSID_MYFRISTCOMGUID =
{0x54bf6567,0x1007,0x11d1,{0xb0,0xaa,0x44,0x45,0x53,0x54,0x00,0x00}};

  GUID的生成可以借助VS下的一个工具GUID生成器,或者利用COM库中的API函数CoCreateGuid,定义如下:

HRESULT CoCreateGuid(
__out GUID *pguid
);

  如果函数创建GUID成功,则返回S_OK,并且pguid将指向所得到的GUID值。实际上CLSID是用来标识COM对象的GUID,CLSID在结构上与GUID一致。(GUID并不是专门用来定义COM对象的,它也用于定义其他实体的标识符)

COM对象的特点

  COM对象与C++对象类似都具有封装性和可重用特性。可重用特性上篇已经提过,COM对象的可重用性是建立在二进制可执行文件的基础上的,而C++对象的可重用性只是建立在源码的基础上。另外,COM对象的实现过程中往往这两种重用性都会用到。

  COM对象的数据成员的封装以组件模块为最终边界,对于对象的用户是完全不可见的,C++对象的封装特性只是语意上的封装,对与对象用户是可见的。

COM接口的定义和标识

  上篇提到,COM对象的客户与对象之间通过接口进行交互,所以组件之间接口的定义至关重要。接口是包含一组函数的数据结构,通过这组数据结构客户代码可以调用组件对象的功能。客户程序用一个指向接口数据结构的指针来调用接口成员函数,实际上接口指针又指向另一个指针,这第二个指针指向一组函数,称为接口函数表,接口函数表中每一项为4字节长的函数指针,指向具体的实现代码。通常把接口函数称为虚函数表(vtable),指向vtable的指针为pvtable,上述关系如图2.1所示。

image

图2.1  接口结构

  与COM对象标识方法一致,COM接口也采用了GUID,不过这里它就称为IID(interface identifier)。如果客户程序要使用一个COM对象的某个接口,则它必须知道该接口的IID和接口所能提供的方法(即接口成员函数)。一般我们采用C++语言来定义接口,如:

class IMyInterface
{
  virtual BOOL MyFunc1() = 0;
  virtual BOOL MyFunc2() = 0;
  virtual void MyFunc3() = 0;
  virtual BOOL MyFunc4() = 0;
};

  C++的class定义中隐藏的this指针可以帮助我们找到pVtable。实际中,COM对象除了这些接口函数外,往往还含有自己的属性数据,这些属性数据反映了对象的状态信息以区别其他对象。然而this指针可以为我们提供COM对象的接口函数,但并不知道this指针如何与对象的状态信息关联起来,所以我们往往用一个自己定义的类来继承接口,如:

class CMyInterfaceClass:public IMyInterface
{
public
  CMyInterfaceClass();
  ~CMyInterfaceClass();
public:
  virtual BOOL MyFunc1();
  virtual BOOL MyFunc2();
  virtual void MyFunc3();
  virtual BOOL MyFunc4();
private:
  BYTE* m_MyData;
  char* m_MyName;
  //other private information
};

  这样可以通过每个接口成员函数所包含一个隐藏的this指针,就可以访问到对象的属性数据了。这样接口与对象之间的结构关系如图2.2所示。

image

图2.2  接口和对象之间的结构关系

  如果一个客户程序使用了两个该对象,显然两个对象公用了成员函数,但属性数据是不能公用的。这时,多个对象与接口之间的结构关系如图2.3所示。

image

图2.3  多个对象与接口之间的结构关系

  如果第二个对象并没有采用CMyInterfaceClass类的结构来实现类似的函数功能,而是另外实现了该接口,则此时多个对象和接口的内存结构关系如图2.4所示。

image

图2.4  不同方法实现的两个该对象与接口的结构关系

  这种把接口指针与对象属性数据绑定在一起的方法并不是唯一的,也可以采用其他方法来实现接口,只要成员中的this指针(即接口指针)与对象数据能建立联系,在接口成员函数中可以访问到对象数据即可。在MFC和ATL中就分别采用了不同的机制来提供对COM接口的支持。

posted @ 2012-01-05 15:18  J_Outsider  阅读(501)  评论(0编辑  收藏  举报