Inside COM学习笔记(二)

原创 2007年10月09日 13:56:00

接口查询
客户同组件的交互都是通过一个接口完成的。在客户查询组件的其他接口时,也是通过接口完成的。这个接口就是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

 

吴恩达机器学习笔记_第二周

多元线性回归的情况: 符号表示方法,上标表示第几个样本,下标表示第几个特征。   多元线性回归的梯度下降: 当代价函数有多个参数时(即多个特征时):   使用梯度下降实用技...
  • hunterlew
  • hunterlew
  • 2016年04月11日 21:31
  • 2901

吴恩达Coursera深度学习课程 DeepLearning.ai 提炼笔记(1-2)-- 神经网络基础

神经网络和深度学习 --------- 神经网络基础
  • Koala_Tree
  • Koala_Tree
  • 2017年09月20日 21:14
  • 3846

我的openwrt学习笔记(一):OpenWrt简介

我的openwrt学习笔记(一):OpenWrt简介     关于 OpenWrt openwrt是嵌入式设备上运行的linux系统。OpenWrt 的文件系统是可写的,开发者无需在每一次修改...
  • xushx_bigbear
  • xushx_bigbear
  • 2015年08月18日 08:45
  • 3818

Inside the C++ Object Model 学习笔记 第五章构造 解构 拷贝语意学

本章主要内容如题目1,对象的构造2,对象的解构3.,拷贝 少量 首先书中给出了一个例子class Abstract_base{public: virtual ~Abstract_base()=0;//...
  • lilin_xdu
  • lilin_xdu
  • 2011年06月10日 10:32
  • 714

Inside the C++ Object Model 学习笔记 第三章 Data语义学

这一章,正如书中所说,研究的是class 的data member 以及 class hierarchy。 class 的 data member ,nostatic member 是“个别class...
  • lilin_xdu
  • lilin_xdu
  • 2011年06月12日 15:15
  • 488

Inside The C++ Object Model学习笔记

P6 +3 C++在布局以及存储事件上主要的额外负担是由virtual引起,包括virtual function机制和virtual base class。此外还有一些多重继承下的额外负担。 P6 ...
  • ayang008
  • ayang008
  • 2012年02月02日 15:56
  • 83

Inside the C++ Object Model 学习笔记 第四章 函数语意学

这章主要讲了以下几个问题1.成员函数的各种调用方式2.虚成员函数3.指向成员函数的指针第一个问题,成员函数的各种调用方法。成员函数 又分为三种,nostatic member, static memb...
  • lilin_xdu
  • lilin_xdu
  • 2011年06月10日 19:35
  • 457

Inside COM读书笔记-----类厂

1.CoCreateInstance      通过传人参数CLSID创建相应组件的一个实例,并返回此组件实例的某个接口。      CoCreateInstance的声明 ...
  • wangqiulin123456
  • wangqiulin123456
  • 2013年05月14日 18:38
  • 2472

Inside COM读书笔记-----调度接口与自动化

1.  一种新的通信方式 IDispatch为客户和组件提供了另外一种通信方式,有了IDispatch后,COM组件可以通过一个标准的接口提供它所支持的服务,而无需提供多个特定与服务的接口。...
  • wangqiulin123456
  • wangqiulin123456
  • 2013年05月22日 21:15
  • 3778

Inside COM读书笔记------引用计数

1.      生命期控制 当使用完一个接口而仍要使用另外一个接口时,是不能将此组件释放掉的。很难知道两个指针是否指向同一个对象。IUnknown的另外两个函数AddRef和Release来...
  • wangqiulin123456
  • wangqiulin123456
  • 2013年05月13日 20:53
  • 1986
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Inside COM学习笔记(二)
举报原因:
原因补充:

(最多只允许输入30个字)