COM之组件创建

2009-1-16 下午14:13

 Pearson Bee

大学时就已经接触了COM,但一直到工作后才有机会将COM理论运用于项目。现在,回归本质,谈谈如何在客户端创建COM组件并返回组件上所支持的接口指针。

我们知道,客户是通过调用COM库函数CoCreateInstance来创建组件并返回接口指针的,但实际上,这个函数首先创建了与所需创建组件相对应的组件,即类厂,再由类厂接口创建‘真正’的组建。在这里,类厂接口是一个派生自IUnknown的借口IClassFactory,它定义了两个纯虚函数CreateInstanceLockServer,其中,用户可以实现CreateInstance,以创建‘真正’的组建。

下面,就用C++来描述整个过程:

一.首先看看CoCreateInstance的实现:

HRESULT CoCreateInstance(const CLSID& clsid,//所要创建的组建的GUID

                        IUnknown *pUnknownOuter,//置零,聚合时用到

                        DWORD dwClsContext,//组件执行上下文

                        const IID& iid,//接口的GUID

                        void **ppv //输出变量,接收返回的接口指针

                        )

{

   *ppv=NULL;

   IclassFactory *pIFactory=NULL;

   HRESULT hr=CoGetClassObject(clsid,

dwClsContext,

NULL,

IID_IclassFactory,

(void **)&pIFactory

);

       If(SUCCEEDED(hr))

       {

          pIFactory->CreateInstance(NULL,iid,(void **)&ppv);

          pIFactory->Release();

       }

       return hr

}

在用户的这个函数里,将真正创建类厂的任务交给了库函数CoGetClassObject,函数CoGetClassObject根据clsid创建了相应的类厂,返回接口指针,赋值pIFactory。之后,就可以使用类厂接口方法CreateInstance创建组件了。那么CoGetClassObject又是如何实现的呢?请看二。

二.CoGetClassObject的实现:

库函数CoGetClassObject实际上调用了封装在dll服务器里的导出函数DllGetClassObject,在DllGetClassObject函数里,我们将会看到类厂的创建过程,在这里使用new操作符生成了一个类厂对象,并使用QueryInterface返回类厂接口IclassFactory的指针。DllGetClassObject的实现如下:

 

   STDAPI DllGetClassObject(const CLSID& clsid,

                       const IID& iid,

                       void **ppv

                      )

{

  *ppv=NULL;//先置零,这是好习惯

   if(clsid!=CLSID_MyComponet)//前面所提到的‘与所要创建组件相对应的

   {                         //类厂’,就表现在这个判断语句里

      return CLASS_E_NOTAVAILABLE;

   }

   HRESULT hr=CFactory *pFactory=new CFactory;//new出一个类厂

   pFactory->QueryInterface(iid,(void **)&ppv);//返回类厂接口指针

   pFactory->Release();

   return hr;

}

 

那么,CoGetClassObject又是如何调用DllGetClassObject的?方法有两种,一是显示调用(LoadLibrary+GetProcessAddress,二是隐式调用(#progma+def),至于这两个方法的实现细节,这里不讲了。

     在第一步中,我们看到,CoCreateInstanc函数里面通过调用所返回类厂接口的方法CreateInstance来创建真正的组件并返回组件接口指针的,即pIFactory->CreateInstance(NULL,iid,(void *)&ppv);那么这个方法又是如何实现的呢?请看三:

三.一般地,我们在实现自己组建的同时,也实现了一个类厂CFactory(它本身也是一个COM组件,因为它所支持的接口IClassFactory派生自IUnknown。在这里将定我们自己的组建名叫Cmpt,类厂名叫CFactory)。

        首先看看IClassFactory的定义:

interface IClassFactory:public IUnknown

{

  virtual HRESULT __stdcall CreateInstance(IUnknown *pUnknownOuter,

                                     const IID& iid,

                                     void **ppv)=0;

 virtual HRESULT __stdcall LockServer(BOOL bLock)=0;

}

    CreateInstance的实现:

class CFactory:public IClassFactory

{

  virtual HRESULT __stdcall QueryInterface(REFIID riid,void **ppv);

  virtual ULONG  __stdcall AddRef(void);

  virtual ULONG  __stdcall Release(void);

 

  virtual HRESULT __stdcall CreateInstance(IUnknown *pUnknownOuter,

                                     const IID& iid,

                                     void **ppv);

 virtual HRESULT __stdcall LockServer(BOOL bLock);

}

HRESULT __stdcall CFactory::CreateInstance((IUnknown *pUnknownOuter,

                                      const IID& iid,

                                      void **ppv)

{

 *ppv=NULL;

  if(pUnknownOuter!=NULL)//必须置NULL

  {

    return CLASS_E_NOAGGREGATION;

  }

  Cmpt *pCmpt=new Cmpt;//在这里,才真正的创建了组件

  HRESULT hr=pCmpt->QueryInterface(iid,(void **)ppv);//返回组件所支持

  pCmpt->Release();                               //的接口指针

  return hf;

}

 

当然,对组件用户来说,没有必要了解组件的创建过程的(事实上,了解它总不是件坏事^_^),可是,对于组件的开发人员来说,那就需要深入了解它了。比如开发DirectShow应用程序,Filter用户没必要了解上述过程,但开发Filter的人员就必须对其内部机制有个清楚的理解。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值