Inside COM学习笔记(二)

接口查询
客户同组件的交互都是通过一个接口完成的。在客户查询组件的其他接口时,也是通过接口完成的。这个接口就是IUnknown。IUnknow接口的定义包含在Win32 SDK中的UNKNWN.H头文件中。
引用如下:

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


在IUnknown中定义了一个名为QueryInterface的函数。客户可以调用QueryInterface来决定组件是否支持某个特定的接口。

关于IUnknown
所有的COM接口都继承了IUnknown,每个接口的vtbl中的前三个函数都是QueryInterface、AddRef和Release。这使得所有的COM接口都可以被当成IUnknown来处理。由于所有的接口都从IUnknown继承的,因此所有的接口都支持QueryInterface。因此组件中的任何一个接口都可以被客户用来获取它所支持的其他接口。

IUnknown指针的获取
CreateInstance函数,它建立一个组件并返回一个IUnknown指针:
IUnknown* CreateInstance();
在创建组件时,客户可以使用CreateInstance而不是使用NEW操作符。

QueryInterface()
IUnknown包含一个名为QueryInterface的成员函数,客户可以通过此函数来查询某个组件是否支持某个特定的接口。若支持,QueryInterface将返回一个指向此接口的指针;否则返回错误的代码。
QueryInterface带有两个参数,其中一个参数也标识客户所需的接口,此参数是一接口标识符的结构(IID)。另外一二指针是QueryInterface存放所请求接口指针的地址。
QueryInterface返回的是一个HRESULT值,此值实际上并不像其名称所表示的那样是标识某个结果的句柄。相反它是一个具有特定结构的32位值客户不应该将QueryInterface的返回值直接同S_OK或E_NOINTERFACE比较,而应使用SUCCEEDED宏或FAILED宏

QueryInterface的使用

在前面定义了interface IX,interface IY,component CA,那么介绍CA所实现的组件中的QueryInterface函数。

void  foo(IUnknown  * pI)
{
 
//Define a pointer to the interface
 IX *pIX = NULL;

 
// ask for interface IX
 HRESULT hr = pI->QueryInterface(IID_IX,(void**)&pIX);
 
 
//check return value
 if(SUCCEEDED(hr))
 

  
//use interface
  pIX->Fx1();
 }

}


QueryInterface()实现

interface  IX:IUnknown {}
interface  IY:IUnknown {} ;
class  CA: public  IX, public  IY {} ;

HRESULT_stdcall CA::QueryInterface(
const  IID &  iid,  void   ** ppv)
{
 
if(iid == IID_IUnknown)
 
{
  
*ppv = static_cast<IX*>(this);
 }

 
 
else if(iid == IID_IX)
 
{
  
*ppv = static_cast<IX*>(this);
 }

 
else if(iid == IID_IY)
 
{
  
*ppv = static_cast<IY*>(this);
 }

 
else
 
{
  
*ppv=null;
  
return  E_NOINTERFACE;
 }

 static_cast
<IUnknown*>(*ppv)->AddRef();
 
return S_OK;
}

 

在代码中第一种情况返回IUnknown指针时,有些人可能会用:

*ppv = static_cast<IUnknown*>(this); (错误的写法)
但是这样将this指针转换为IUnknown指针是不明确的。因为IX和IY都是从IUnKnown继承得到的。CA使用了多重继承。

 

一个完整的例子

 

********** IUnknown.cpp ***********************
//
//  IUnknown.cpp
//  To compile use: cl IUnknown.cpp UUID.lib
//
#include  < iostream.h >
#include 
< objbase.h >

void  trace( const   char *  msg)  { cout << msg << endl ;}


//  Interfaces
interface  IX : IUnknown
{
 
virtual void __stdcall Fx() = 0 ;
}
 ;

interface  IY : IUnknown
{
 
virtual void __stdcall Fy() = 0 ;
}
 ;

interface  IZ : IUnknown
{
 
virtual void __stdcall Fz() = 0 ;
}
 ;

//  Forward references for GUIDs
extern   const  IID IID_IX ;
extern   const  IID IID_IY ;
extern   const  IID IID_IZ ;

//
//  Component
//
class  CA :  public  IX,
           
public  IY
{
 
//IUnknown implementation
 virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv) ;  

 
 
virtual ULONG __stdcall AddRef() return 0 ;}
 
virtual ULONG __stdcall Release() return 0 ;}

 
// Interface IX implementation
 virtual void __stdcall Fx() { cout << "Fx" << endl ;}

 
// Interface IY implementation
 virtual void __stdcall Fy() { cout << "Fy" << endl ;}
}
 ;

HRESULT __stdcall CA::QueryInterface(
const  IID &  iid,  void **  ppv)
{  
 
if (iid == IID_IUnknown)
 
{
  trace(
"QueryInterface: Return pointer to IUnknown.") ;
  
*ppv = static_cast<IX*>(this) ;
 }

 
else if (iid == IID_IX)
 
{
  trace(
"QueryInterface: Return pointer to IX.") ;
  
*ppv = static_cast<IX*>(this) ;
 }

 
else if (iid == IID_IY)
 
{
  trace(
"QueryInterface: Return pointer to IY.") ;
  
*ppv = static_cast<IY*>(this) ;
 }

 
else
 
{      
  trace(
"QueryInterface: Interface not supported.") ;
  
*ppv = NULL ;
  
return E_NOINTERFACE ;
 }

 reinterpret_cast
<IUnknown*>(*ppv)->AddRef() ; // See Chapter 4.
 return S_OK ;
}


//
//  Creation function
//
IUnknown *  CreateInstance()
{
 IUnknown
* pI = static_cast<IX*>(new CA) ;
 pI
->AddRef() ;
 
return pI ;
}


//
//  IIDs
//
//  {32bb8320-b41b-11cf-a6bb-0080c7b2d682}
static   const  IID IID_IX  =  
 
{0x32bb83200xb41b0x11cf,
 
{0xa60xbb0x00x800xc70xb20xd60x82}}
 ;

//  {32bb8321-b41b-11cf-a6bb-0080c7b2d682}
static   const  IID IID_IY  =  
 
{0x32bb83210xb41b0x11cf,
 
{0xa60xbb0x00x800xc70xb20xd60x82}}
 ;

//  {32bb8322-b41b-11cf-a6bb-0080c7b2d682}
static   const  IID IID_IZ  =  
 
{0x32bb83220xb41b0x11cf,
 
{0xa60xbb0x00x800xc70xb20xd60x82}}
 ;

//
//  Client
//
int  main()
{
 HRESULT hr ;

 trace(
"Client:         Get an IUnknown pointer.") ;
 IUnknown
* pIUnknown = CreateInstance() ;

   
 trace(
"Client:         Get interface IX.") ;

 IX
* pIX = NULL ; 
 hr 
= pIUnknown->QueryInterface(IID_IX, (void**)&pIX) ;
 
if (SUCCEEDED(hr))
 
{
  trace(
"Client:         Succeeded getting IX.") ;
  pIX
->Fx() ;          // Use interface IX.
 }



 trace(
"Client:         Get interface IY.") ;

 IY
* pIY = NULL ;
 hr 
= pIUnknown->QueryInterface(IID_IY, (void**)&pIY) ;
 
if (SUCCEEDED(hr))
 
{
  trace(
"Client:         Succeeded getting IY.") ;
  pIY
->Fy() ;          // Use interface IY.
 }



 trace(
"Client:         Ask for an unsupported interface.") ;

 IZ
* pIZ = NULL ;
 hr 
= pIUnknown->QueryInterface(IID_IZ, (void**)&pIZ) ;
 
if (SUCCEEDED(hr))
 
{
  trace(
"Client:         Succeeded in getting interface IZ.") ;
  pIZ
->Fz() ;
 }

 
else
 
{
  trace(
"Client:         Could not get interface IZ.") ;
 }



 trace(
"Client:         Get interface IY from interface IX.") ;

 IY
* pIYfromIX = NULL ;
 hr 
= pIX->QueryInterface(IID_IY, (void**)&pIYfromIX) ;
 
if (SUCCEEDED(hr))
 

  trace(
"Client:         Succeeded getting IY.") ;
  pIYfromIX
->Fy() ;
 }



 trace(
"Client:         Get interface IUnknown from IY.") ;

 IUnknown
* pIUnknownFromIY = NULL ;
 hr 
= pIY->QueryInterface(IID_IUnknown, (void**)&pIUnknownFromIY) ;
 
if (SUCCEEDED(hr))
 
{
  cout 
<< "Are the IUnknown pointers equal?  " ;
  
if (pIUnknownFromIY == pIUnknown)
  
{
   cout 
<< "Yes, pIUnknownFromIY == pIUnknown." << endl ;
  }

  
else
  
{
   cout 
<< "No, pIUnknownFromIY != pIUnknown." << endl ;
  }

 }


 
// Delete the component.
 delete pIUnknown ;

 
return 0 ;
}



在链接此程序时,需要将其同UUID.LIB一块链接以获取IUnknown的接口表示符的定义。
命令行编译:cl IUnknown.cpp UUID.lib

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值