com学习笔记(2)基本的com接口QueryInterface的实现

QueryInterface   接上篇

一.COM接口的开始IUnknown

com起于接口,又归于接口.

com之所以是com,是因为其继承了一个名为IUnknown接口 .

IUnknown接口是一个非常有趣的名字.我们第一次看到这个接口,都会非常好奇,名字的由来开发内部肯定是有故事的,或者他们想不出啥好名字也是有可能的.

下面我们来看一下IUnknown接口定义了哪些成员,这篇只讲QueryInterface

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

};

二.QueryInterface的实现与使用

1.作用

看命名就可以猜这个方法是用来查询组件是否支持某个特定接口。若支持泽返回指向此接口的指针。

2.参数

QueryInterface方法有两个参数,

第一个为接口标识符,简称IID,全名(Interface Identifier),现在可以只理解为一个常量

第二个参数即为返回的接口指针

3.使用方法

我们先来看示例代码

定义一个继承自IUnknown接口的IX

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

若CA实现了该IX接口,则使用如下

static const 
IID IID_IX = 
{0x32bb8320, 0xb41b, 0x11cf,
{0xa6, 0xbb, 0x0, 0x80, 0xc7, 0xb2, 0xd6, 0x82}} ;

void foo(IUnknown* pI)
{
IX* pIX=NULL;
HRESULT hr=pI->QueryInterface(IID_IX,(void **)&pIX);

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

3.1 HRESULT

HRESULT是一个查询结果状态集合,并非true或false可以表示的,所以用SUCCEEDED方法来判断查询结果是否成功,失败的话,接口指针为NULL.

4.QueryInterface的实现

CA继承了IX,由于IX继承了IUnknown接口,所以CA也必须实现IUnknown接口成员,我们重新来看一下QueryInterface方法的参数

virtual HRESULT __stdcall QueryInterface(const IID& iid, void ** ppv) =0;

该方法会根据传输不同iid,而返回相对应的接口指针,为了演示,我们再定义一个接口IY,CA实现IX和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;
}
return S_OK ;
}

是不是很简单?,获取到以后用static_cast 来转换类型。IID_IUnknown,S_OK,E_NOINTERFACE等都是内置的状态码

5.简单创建IUnknown

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

6.调用接口

int 
main()
{
HRESULT hr ;
IUnknown* pIUnknown = CreateInstance() ;

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

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

// Delete the component.
delete pIUnknown ;
return 0 ;
}

三.QueryInterface实现准则


1.QueryInterface返回的总是同一IUnknown指针 ,贴图了

image

2.若用户曾获取过某个接口,那么它将总能获取此接口

3.用户可获取再次获取过的接口

image

image

4.用户可以返回到起始接口

image

3和4都可以理解为接口之间的切换。

5.接口可获取- 获取到 接口的接口

通过A接口得到B接口,B接口可以获取C接口,那么A接口可以直接获取C接口.

image
image

以上就如数学公式一般,犹如com编程的不变真理.

原文地址:https://www.cnblogs.com/dongzhiquan/p/1994756.html