COM技术3

        这一章主要介绍QueryInterface函数,我觉得其中最重要的是了解程序的整体结构.即包含哪几个文件,每个文件有哪些类,每个类是做什么的.书中有个完整的例子.代码如下:

#include  < iostream.h >
#include 
< objbase.h >
// To Compile use:cl IUnknown.cpp UUID.lib
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;
}
;

extern   const  IID IID_IX;
extern   const  IID IID_IY;
extern   const  IID IID_IZ;

// Component
class  CA: public  IX, public  IY
{
    
virtual HRESULT _stdcall QueryInterface(const IID& iid, void** ppv);
    
virtual ULONG _stdcall AddRef(){return 0;}
    
virtual ULONG _stdcall Release(){return 0;}

    
//interfac IX implementation
    virtual void _stdcall Fx(){cout<<"Fx()"<<endl;} 

    
//interfac IY implementation
    virtual void _stdcall Fy(){cout<<"Fy()"<<endl;} 
}
;

HRESULT _stdcall CA::QueryInterface(
const  IID &  iid,  void **  ppv)
{
    
if (iid == IID_IUnknown)
    
{
        trace(
"QuerInterface: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();
    
return S_OK;
}


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


// IIDs

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

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

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

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();
    }


    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();
    }


    trace(
"Client: Ask for an unsuppoered interface.");
    IZ 
*pIZ = NULL;
    hr 
= pIUnknown->QueryInterface(IID_IZ,(void**)&pIZ);
    
if (SUCCEEDED(hr))
    
{
        trace(
"Client: Succeeded getting 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 interface 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;
}

/*输出结果
Client: Get an IUnknown pointer.
Client: Get Interface IX.
QueryInterface: Return pointer to IX.
Client: Succeeded getting IX.
Fx()
Client: Get Interface IY.
QueryInterface: Return pointer to IY.
Client: Succeeded getting IY.
Fy()
Client: Ask for an unsuppoered interface.
QueryInterface: Interface not supported.
Client: Could not get interface IZ.
Client: Get interface IY from interface IX.
QueryInterface: Return pointer to IY.
Client: Succeeded getting IY.
Fy()
Client: Get interface IUnknown from interface IY.
QuerInterface:Return pointer to IUnknown
Are the IUnknown pointers equal? Yes,pIunknownfromIY == pIunknown.
Press any key to continue
*/

 

其实我们可以把这一个文件按其功能划分为更下的文件,这样对整体结构有个清晰的认识:

接口类 interface.h

#include  < objbase.h >

// 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;
}
;

// IIDs
static   const  IID IID_IX  =  
{
    
0x32bb8320,0xb41b,0x11cf,{0xa6,0xbb,0x0,0x80,0xc7,0xb2,0xd6,0x82}
}
;
static   const  IID IID_IY  =  
{
    
0x32bb8321,0xb41b,0x11cf,{0xa6,0xbb,0x0,0x80,0xc7,0xb2,0xd6,0x82}
}
;
static   const  IID IID_IZ  =  
{
    
0x32bb8322,0xb41b,0x11cf,{0xa6,0xbb,0x0,0x80,0xc7,0xb2,0xd6,0x82}
}
;

 

实现类 --头文件CB.h

#ifndef CB_H 
#define  CB_H
#include 
" interface.h "
#include 
< iostream.h >

// Component
class  CB: public  IX, public  IY
{
    
virtual HRESULT _stdcall QueryInterface(const IID& iid, void** ppv);
    
virtual ULONG _stdcall AddRef(){return 0;}
    
virtual ULONG _stdcall Release(){return 0;}

    
//interfac IX implementation
    virtual void _stdcall Fx(){cout<<"Fx()"<<endl;} 

    
//interfac IY implementation
    virtual void _stdcall Fy(){cout<<"Fy()"<<endl;} 
}
;

extern   void  trace( const   char *  msg);

// Creation function
extern  IUnknown *  CreateInstance();

#endif

 

实现类--CB.cpp 

#include  " CB.h "

HRESULT _stdcall CB::QueryInterface(
const  IID &  iid,  void **  ppv)
{
    
if (iid == IID_IUnknown)
    
{
        trace(
"QuerInterface: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();
    
return S_OK;
}


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

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

注意将this指针转换为IUnknown*是不明确的.因为IX和IY都是从IUnknown继承得到的.因此在这种情况下,返回值应该是static_cast<IUnknown*>(static_cast<IX*>(this))或static_cast<IUnknown*>(static_cast<IY*>(this)),不过在上例中其实是无关紧要的,因为它们使用的是同一实现.

客户端代码--App.cpp

#include  " CB.h "

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();
    }


    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();
    }


    trace(
"Client: Ask for an unsuppoered interface.");
    IZ 
*pIZ = NULL;
    hr 
= pIUnknown->QueryInterface(IID_IZ,(void**)&pIZ);
    
if (SUCCEEDED(hr))
    
{
        trace(
"Client: Succeeded getting 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 interface 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;
}

 

可以看到,在接口类中,我们定义了三个接口,定义了三个IID.

在具体实现类中,实现了QueryInterface,AddRef,Release三个IUnknown接口,这是COM组件必须实现的接口,另外还实现了Fx和Fy接口.在实现类中实现QueryInterface是必要的,因为只有在实现类中,才知道这个实现类到底实现了哪些接口.

在客户端代码中,通过QueryInterface接口可以查询当前实现类有没有实现某个接口.注意QueryInterface的实现方式.对this指针的类型转换会给ppv不同的值.也就是

(IX * ) this   !=  (IY * ) this
(
void * ) this   !=  (IY * ) this

 

比如如下定义中:


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

void  foo(IX *  pIX);
void  bar(IY *  pIY);

int  main()
{
    CA 
*pA = new CA;
    foo(pA);
    bar(pA);
    delete pA;
    
return 0;
}

由于CA同时继承了IX和IY,因此可以使用IX或IY指针的地方均可以使用指向CA的指针.例如可以将指向CA的指针传给接收IX或IY指针的函数,这样此函数仍将能正常工作.foo需要一个指向合法的IX的虚拟函数表的指针,而bar则需要一个指向IY虚拟函数表的指针.这两个虚拟函数表的内容是不一样的.因此将一个IX vtbl传给bar时,此函数不能正常工作.因此编译器将同一指针传给foo和bar是不可能的,它必须对CA的指针进行修改以便它指向一个合适的vtbl指针.下图显示了类CA的内存结构.

由上图可以看出,CA的this指针指向IX的虚拟函数表.因此可以在不改变CA的this指针的值的情况下用它来代替IX指针.但也可以很明显的看出,CA的this指针并没有指向IY的虚拟函数表指针.因此将指向类CA的指针传给一个接收IY指针的函数之前,其值必须修改.为完成这种修改,编译器将把IY虚拟函数表指针的偏移量加到CA的this指针上.

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值