COM入门

COM的Interface: 1)继承自IUnknown。2)vtbl中前3个函数:QuereyInterface,AddRef和Release。

interface   IUnknown
{
         virtual      HRESULT      __stdcall  QueryInterface(const  IID && iid,  void  * *ppv) = 0;
         virtual      ULONG         __stdcall  AddRef() =  0;
         virtual      ULONG         __stdcall  Release() =  0;
}

一,引用计数简介:
AddRef 和 Release实现的是一种名为引用计数器的内存管理技术。引用计数是使组件能将自身删除最简单也是效率最高的方法。
计数器使用规则:
1、返回之前调用AddRef();
2、使用完接口调用Release();
3、赋值之后调用AddRef。再将一个接口指针赋给另一个接口指针时,应调用AddRef。

二,QueryInterface函数
HRESULT  __stdcall QueryInterface(const IID&iid,void **ppv);

stdcall约定:1)参数从右向左压入栈,2)函数自身修改堆栈 3)函数名自动加前导的下划线,后面紧跟一个@符号,其后紧跟着参数的尺寸。

iid:接口标志符。

ppv:用来存放所请求接口的地址。

返回值:S_OK 或 E_NOINTERFACE, 用SUCEEDED或者FAILED宏验证是否成功。HRESULT为一个可以分为三个域的32位值。

使用方法:假如知道一个指向IUnknown接口的指针pI,传给它一个接口标志符即可

例如:

ContractedBlock.gif ExpandedBlockStart.gif Code
None.gifvoid Foo(IUnknown * pI)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif    IX 
* pIX = NULL;
InBlock.gif
InBlock.gif    HRESULT hr 
= pI->QueryInterface(IID_IX,(void **)pIX);
InBlock.gif
InBlock.gif 
if(SUCCEEDED(hr))
ExpandedSubBlockStart.gifContractedSubBlock.gif 
dot.gif{
InBlock.gif      pIX
->FX();
ExpandedSubBlockEnd.gif     }

ExpandedBlockEnd.gif}

None.gif
None.gif
//QueryInterface的实现。
None.gif

None.gifHRESULT _stdcall  CA::QueryInterface(
const    IID&iid,void **ppv)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif 
if(iid == IID_IUnknown)
ExpandedSubBlockStart.gifContractedSubBlock.gif 
dot.gif{
InBlock.gif 
*ppv = static_cast<IX *>(this);
ExpandedSubBlockEnd.gif    }

InBlock.gif 
else if(iid == IID_IX)
ExpandedSubBlockStart.gifContractedSubBlock.gif 
dot.gif{
InBlock.gif 
*ppv = static_cast<IX *>(this);
ExpandedSubBlockEnd.gif    }

InBlock.gif 
else if(iid == IID_IY)
ExpandedSubBlockStart.gifContractedSubBlock.gif 
dot.gif{
InBlock.gif 
*ppv = static_cast<IY *>(this);
ExpandedSubBlockEnd.gif    }

InBlock.gif 
else if(iid == IID_IUnknown)
ExpandedSubBlockStart.gifContractedSubBlock.gif 
dot.gif{
InBlock.gif 
*ppv = NULL;
InBlock.gif 
return E_NOINTERFACE;
ExpandedSubBlockEnd.gif    }

InBlock.gif
InBlock.gif    static_cast 
<IUnknown *> (* ppv)->AddRef();
InBlock.gif    retru S_OK;
InBlock.gif
ExpandedBlockEnd.gif}
 
None.gif

多重继承及类型转换:通常将一种类型的指针转换为另一种类型并不会改变它的值。为了支持多重继承,某些情况下,C++必须改变类指针的值。假如一个类定义如下:

class CA: public IX,public IY{...};

下图显示了CA对象的内存结构。
2.jpg

 

GUID:是一个128位16字节的GUID结构。
MS提供两个工具生成GUID,一个是UUIDGEN。EXE   另一个是 GUIDGEN.EXE。
定义一个GUID:
extern "C"    const   IID      IID_IX  =  { .....}
声明:
extern "C"   congst   IID      IID_IX;
或者宏
DEFINE_GUID(IID_IX, .....);
将一个GUID做为组件标志符。
IUnknown    *    CoCreateInstance(.....);
com中用以标志组件的GUID被称为类标志符,用CLSID与IID区分。
通过引用传递GUID。


注册表的使用:
CoCreateInstance将利用CLSID作为关键字在注册表中找所需文件名。
com只用了这册表的一个分支:HKEY_CLASSES_ROOT,  其下有一个CLSID关键字,其下列有系统中安装的所有组件的CLSID。

 

com库

所有com组件和客户需要一些相同操作,为保证这些操作是按标准来的,com定义了一个函数库来实现所有这些操作。此函数库是在 ole32.dll中实现的。在使用静态链接时,可以使用ole32.lib。
com库的初始化,除了CoBuildVersion必须首先调用CoInitialize来初始化com库函数。当进程不再需要库函数时,必须调用CoUninitialize。
对于一个进程只需初始化一次com库,如果多次初始化,必须保证每个都有对应的CoUninitialize.
OleInitialize基于com,增添了更多功能。

类厂
创建一个组件最简单的方法

1,创建一个组件最简单的方法:用 CoCreateInstanc函数.因此CoCreateInstanc也是创建组件用的最多的一种方法.但其灵活性有限,不能满足所有组件的需求. 这就是为什么要引入类厂.

所有组件都是用类厂创建的.  CoCreateInstanc也是按照一般方法通过类厂来创建组件的.

2. CoCreateInstanc

com库中包含一个创建组件的名为CoCreateInstanc的函数.

定义如下:

HRESULT __stdcall CoCreateInstanc(

   const CLSID & clsid,
   IUnknown * pIUnknown,   //outer component
   DWORD  dwClsContext,    //server context
   const IID &iid,
   void ** ppv
);

看以看到有四个输入参数一个输出参数.
第一个待创建组件的CLSID.
第二个是用来聚合组件的.
第三个是用来限定所创建组件的执行上下文.
第四个是组件待使用的接口的IID;
CoCreateInstanc将在最后一个参数中返回此接口指针.
将一个IID 传给CoCreateInstanc,客户将无需在创建组件后再调用QueryInterface;

3.CoCreateInstanc的使用

  IX *pIX = NULL;
  HRESULT  hr = CoCreateInstanc(CLSID_component1,
                                NULL,
                                CLSCTX_INPROC_SERVER,
                                IID_IX,
                                (void **)&pIX);

  if(SUCCEEDED(hr))
{
  pIX->Fx();
  pIX->Release();
  }

该例子创建了一个由CLSID_component1标志的组件.
此处不需要聚合组件,因此第二个参数之NULL;
我们用IID_IX来表示希望得到接口IIX的指针,CoCreateInstanc将把此指针返回在pIX变量中,若成功返回则可用该接口.Release()表示对接口和组件的使用已经完成.

类上下文

CoCreateInstanc的第三个参数可以控制所创建的组件是在客户创建的进程中运行,还是在不同进程中.或者在另外一台机器上.

该参数可以由一下几个值组合:

CLSCTX_INPROC_SERVER,
CLSCTX_INPROC_HANDLER,
CLSCTX_LOCAL_SERVER,
CLSCTX_REMOTE_SERVER;
客户可以在三种不同上下文中使用某个组件: 进程中,本地,远程.

为什么用类厂

1.CoCreateInstance的不灵活.
  我们知道 CoCreateInstance创建组件的过程是:传给他一个CLSID,然后它创建相应的组件.,并返回所请求接口的指针,.CoCreateInstance没有提供一种可以控制组件创建过程的的方法.
  存在问题: 我们不能控制组件创建过程.
  解决方案: 使用一个专门创建组件的组件,既 类厂.

2.类厂.

实际上CoCreateInstance并没有创建组件,而是创建了一个被称为类厂的组件.
类厂唯一功能就是创建其他组件.

精确点讲就是.某个特定类厂将创建某个特定CLSID相应的组件. 客户可以通过类厂所支持的接口来对类厂创建组件的过程加以控制. 创建组件的标准接口是 IClassFactory,用CoCreateInstance创建的组件实际上是通过IClassFactory来创建的.

3.CoGetClassObject

要创建一个组件,首先要创建类厂本身.

   CoCreateInstance()用来创建与指定CLSID的组件,并返回指向组件某个接口的指针.
   与CoCreateInstance类似,用CoGetClassObject() 来创建与指定CLSID的类厂,并返回指向类厂某个接口的指针.

  函树定义如下:
  HRESULT __stdcall 用CoGetClassObject(

   const CLSID & clsid,
   DWORD  dwClsContext,    //server context
   COSERVERINFO *pServerInfo,  //Resevred for DCOM
   const IID &iid,
   void ** ppv
);

客户用 CoCreateInstanc 所返回的指针来创建所需的组件,这个指针通常是一个IClassFactory指针.
3.IClassFactory
类厂所支持的用于创建组件的标准接口是 IClassFactory.大部分组件可以通过它来创建.
声明如下:
interface IClassFactory :IUnknown
{
  HRESULT stdcall  CreateInstace(IUnknown * pUnknownOuter,
                  const IID &iid,
                  void **ppv);
  HRESULT stdcall LockServer(bool bLock);
  };
4.为什么要用用CoGetClassObject
大多数情况下使用 CoCreateInstanc 创建组件,而不使用CoGetClassObject。但是在以下两种情况  下应使用CoGetClassObject而不使用 CoCreateInstanc 。
1、若想用不同于 IClassFactory 的某个创建接口来创建组件,则必须使用CoGetClassObject。
2、若需要创建同一组件的多个不同实例,使用CoGetClassObject可以取得较高效率。因为这样只需相应组件的类厂一次,而CoCreateInstanc 需要为每个实例分别创建并释放相应的类厂。
另外,CoGetClassObject可以对组件的创建过程进行更多的控制。

类厂实现

1、CoGetClassObject使用DllGetClassObject来创建类厂。声明如下:
STDAPI    DllGetClassObject (
                                const   CLSID &clsid,
                                const   IID &  iid,
                                void  **  ppv  );
2、组件的创建过程
客户调用 CoGetClassObject----〉com库调用DllGetClassObject ------>返回给客户IClassFactory------>客户调用 IClassFactory::CreateInstance------>返回给客户 IX---------〉客户调用IX::FX.

转载于:https://www.cnblogs.com/dubingsky/archive/2009/06/16/1504485.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值