zoukankan      html  css  js  c++  java
  • 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编程的不变真理.

  • 相关阅读:
    算法之路 level 01 problem set
    算法原理与实践(链表)
    散列表(HashTable)
    系统设计与实践(实战演练)
    桶排序 + 基数排序
    算法原理与实践(二叉树)
    Total Difference String
    【翻译】std::list::remove
    【翻译】std::remove
    Observer模式实践
  • 原文地址:https://www.cnblogs.com/Clingingboy/p/1517222.html
Copyright © 2011-2022 走看看