接口查询 客户同组件的交互都是通过一个接口完成的。在客户查询组件的其他接口时,也是通过接口完成的。这个接口就是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
=
...
{ 0x32bb8320 , 0xb41b , 0x11cf , ... { 0xa6 , 0xbb , 0x0 , 0x80 , 0xc7 , 0xb2 , 0xd6 , 0x82 } }
;
//
{32bb8321-b41b-11cf-a6bb-0080c7b2d682}
static
const
IID IID_IY
=
...
{ 0x32bb8321 , 0xb41b , 0x11cf , ... { 0xa6 , 0xbb , 0x0 , 0x80 , 0xc7 , 0xb2 , 0xd6 , 0x82 } }
;
//
{32bb8322-b41b-11cf-a6bb-0080c7b2d682}
static
const
IID IID_IZ
=
...
{ 0x32bb8322 , 0xb41b , 0x11cf , ... { 0xa6 , 0xbb , 0x0 , 0x80 , 0xc7 , 0xb2 , 0xd6 , 0x82 } }
;
//
//
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