com编程基础和QueryInterface函数的实现原理例子

所有的com接口都继承IUnknown接口,接口定义在win32SDK UNKNWN.h文件中
interface IUnknown{
    virtual HRESULT _stdcall QueryInterface(const&IID iid,void *ppv) = 0;
    virtual ULONG _stdcall AddRef()=0;
    virtual ULONG _stdcall Release() = 0;
}
由于所有的com接口都继承了IUnknown,每个接口的vtbl(虚拟函数表)中的前三个函数都是
QueryInterface AddRef Release,所有的com接口可以被当成IUnknown接口处理。某个接口的
vtbl中的前三个函数不是这三个,它将不是一个com接口。

IUnknown获取 IUnknown* CreateInstance();

QueryInterface函数,客户可以通过此函数查询某个组件是否支持某个特定的接口。支持则返回
一个指向此接口的指针。否则返回一个错误代码,客户可以接着查询其他接口或将组件卸载。

QueryInterface带有两个参数,此参数是一个接口标识符IID 结构
另外一个是需要请求的接口指针。

QueryInterface函数的实现是根据IID 转换成对应的接口指针
if(iid == IID_IX){
    *ppv = static_cast<IX*>(this)
}else if(iid = IID_IY){
    *ppv = static_cast<IY*>(this)
}

QueryInterface实现规则
QueryInterface 返回的总是同一个IUnknown指针
若客户曾经获取某个接口,那么总能获取此接口
客户可以再次获取已经拥有的接口
客户可以返回到起始接口
若能够从某个接口获取某特定接口,那么可以从任意接口都将可以获取此接口



组件实例只有一个IUnknown接口,当查询组件实例的IUnknown接口时,不论通过哪个接口,所得到的是同一指针值。
为确定两个接口是否指向同一组件,可以通过两个接口查询IUnknown接口,将返回值进行比较。

#include <iostream>
#include <ObjBase.h>
using namespace std;
void trace(const char* msg){cout<<msg<<endl;}
//从其它人意接口都可以使用QueryInterface 来获取CA所实现的任意接口
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;

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;}
    virtual void _stdcall Fx(){cout <<"Fx"<<endl;}
    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();
    return S_OK;
}

IUnknown * CreateInstance()
{
    IUnknown*pI = static_cast<IX*>(new CA);
    pI->AddRef();
    return pI;
}
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();//IUnknown是一个指向子类CA 的基类指针
    trace("client:    Get interface Ix.");
    IX* pIX = NULL;
    hr = pIUnknown->QueryInterface(IID_IX,(void**)&pIX);//pIUnknown 是指向子类CA的指针 继承了接口IX IY 所以可以找到 组件IX IY 也就是可以将指针强转成子类指针
    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 unsupported interface.");
    IZ* pIZ = NULL;
    hr = pIUnknown->QueryInterface(IID_IZ,(void**)&pIZ);
    if (SUCCEEDED(hr))
    {
        trace("client:    Succeede in getting interface IZ.");
        pIZ->Fz();
    }
    else
    {
        trace("client: Could not get interface IZ.");
    }


    trace("Client:    GetInterface 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* pIunknownIY = NULL;
    hr = pIY->QueryInterface(IID_IUnknown,(void**)&pIunknownIY);
    if (SUCCEEDED(hr))
    {
        cout<<"Are the IUnknown pointers equeal?  ";
        if (pIunknownIY == pIUnknown)
        {
            cout<<"yes PIUnknownFromIy == pIunknown. "<<endl;
        }else{
            cout<<"No,pIUnknownFromIy != pIunknown."<<endl;
        }

    }
    getchar();
    delete pIUnknown;
    return 0;
}




































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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值