COM类厂的作用和创建

介绍了怎么样用动态链接库去实现COM,但组件对我们来说仍是不透明的,我们需要知道实现组件DLL的位置,必须自己来加载组件的CreateInstance函数来获得组件的指针.在书中第一篇就曾经提到过:COM组件可以透明地在网络上(或本地)被重新分配位置,而不会影响本地客户程序.所以,由客户端来调用DLL并不是什么好主意.必须有一种更好的办法让组件的实现更透明,更灵活!
    
于是,就引入了类厂的概念.什么是类厂,类厂也是一个接口,它的职责是帮我们创造组件的对象.并返回给客户程序一个接口的指针.每个组件都必须有一个与之相关的类厂,这个类厂知道怎么样创建组件.当客户请求一个组件对象的实例时,实际上这个请求交给了类厂,由类厂创建组件实例,然后把实例指针交给客户程序。这么说有点难明白.先看一个伪实例.
 1.
实现二个接口IXIY        (上二节中有详细介绍
)
 2.
实现一个组件CA,实现了IXIY接口.    (上二节中有详细介绍)

 3.
对于这个组件进行注册,把组件的信息加入到注册表中.
     
实现DllRegisterServerDllUnregisterServer函数.函数具体功能就是把本组件的CLSID,ProgID,DLL的位置放入注册表中.这样程序就可以通过查询注册表来获得组件的位置
.
 4.
创建本组件类厂的实例

class CFactory:public IClassFactory
{
 virtual HRESULT __stdcall QueryInterface(const IID& iid,void** ppv);
 virtual ULONG   __stdcall AddRef();
 virtual ULONG   __stdcall Release();

 virtual HRESULT __stdcall CreateInstance(IUnknown* pUnknownOuter,
  const IID& iid,
  void** ppv);
}
 
在类厂实例中,主要的功能就是CreateInstance了,这个函数就是创建组件的相应实例.看它的实现:
HRESULT __stdcall CFactory::CreateInstance(IUnknown* pUnknownOuter,const IID& iid,void** ppv)
{
   //...
 CA* pA = new CA;
 if(pA == NULL)
  return E_OUTOFMEMORY;
 HRESULT hr = pA->QueryInterface(iid,ppv);

 pA->Release();
 return hr;
}

 5.在这个组件的DLL中导出DllGetClassObject函数.这个函数的功能就是创建类厂的实例对象并查询接口.看其实现:
STDAPI DllGetClassObject(const CLSID& clsid,
       const IID& iid,
       void** ppv)
{
 //....
 CFactory* pFactory = new CFactory();

 if(pFactory == NULL)
  return E_OUTOFMEMORY;

 HRESULT hr = pFactory->QueryInterface(iid,ppv);
 pFactory->Release();
 return hr;
}

组件的实现差不多就这么多,下面在客户端怎么调用组件呢?这就需要用到COM函数库了,由COM函数库去查找注册表,调用组件的类厂,创建组件实例,返回接口.如下所示:
IUnknown* pUnk = NULL;
IX* iX = NULL;
CoInitialize(NULL);
CoCreateInstance(CLSID_Component1,CLSCTX_INPROC_SERVER,IID_IUnknown,(void**)&pUnk);
pUnk->QueryInterface(IID_IX,(void**)&iX);
pUnk->Release();
iX->Fx();
iX->Release();
CoUninitialize();

至于客户是通过CoCreateInstance怎么获得组件的类厂,创建组件实例的.下面摘录的一篇文章很清晰的说明了这一切:
-------------------------------------------------------------------------------------
这部分我们将构造一个创建COM组件的最小框架结构,然后看一看其内部处理流程是怎样的

COM组件的运行机制,即COM是怎么跑起来的。
    IUnknown *pUnk=NULL;
    
IObject *pObject=NULL;
    
CoInitialize(NULL);
    
CoCreateInstance(CLSID_Object, CLSCTX_INPROC_SERVER, NULL, IID_IUnknown, (void**)&pUnk);
    
pUnk->QueryInterface(IID_IOjbect, (void**)&pObject);
    
pUnk->Release();
    
pObject->Func();
    
pObject->Release();
    
CoUninitialize();
  CoCreateInstance身上,让我们来看看它内部做了一些什么事情。以下是它内部实现的一个伪代码:

    CoCreateInstance(....)
    
{
     
.......
     
IClassFactory *pClassFactory=NULL;
     
CoGetClassObject(CLSID_Object, CLSCTX_INPROC_SERVER, NULL, IID_IClassFactory, (void **)&pClassFactory);
     
pClassFactory->CreateInstance(NULL, IID_IUnknown, (void**)&pUnk);
     
pClassFactory->Release();
     
........
    
}

  这段话的意思就是先得到类厂对象,再通过类厂创建组件从而得到IUnknown指针。

  继续深入一步,看看CoGetClassObject的内部伪码:

    CoGetClassObject(.....)
    
{
      //

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值