zoukankan      html  css  js  c++  java
  • 【COM学习】之一、QueryInterface

    开始先说一句,学习com之前要学好c++ 对象模型。


    QueryInterface的使用:

    QueryInterface是IUnknown的一个成员函数,客户可以通过此函数来查询某个组件是否支持某个特定的接口。

    QueryInterface成功返回一个指向此接口的指针。     错误返回一个错误代码。


    HRESULT _stdcall QueryInterface(const IID& iid, void **ppv);


    下面是一个QueryInterface的使用实例:(可知道相应的组件是否支持某个特定的接口)

    void ceshi(IUnknown * pI)
    {
           IX* pIX = NULL;
           HRESULT hr = pI->QueryInterface(IID_IX, (void**)&pIX);
           if(SUCCEEDED(hr))
           {
                  pIX->Fx();
           }
    }

    我们查询pI 是否支持由IID_IX所标识的接口。

    代码中主意的是   pIX需要初始化为NULL, 这是一种比较好的编程方法,在后面的实现中我们会看到  QueryInterface在失败时将把返回的接口指针置为NULL。

    由于QueryInterface是由程序员而不是由系统实现的,因此某些组件可能并不会在查询失败时将此指针置为NULL。    为了安全,在程序中还是我们自己将其置为NULL比较好。



    QueryInterface的实现:

       他的实现需要完成的不过是根据某个给定的IID返回指向相应接口的指针。

    若组件支持客户指定的接口,那么应返回S_OK 以及相应的指针。

    若不支持,返回值应为: E_NOINTERFACE 并将相应的指针返回值置为NULL。

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


    QueryInterface 的末尾调用AddRef实际上没有任何作用,后面讨论 AddRef;


    QueryInterface的实现规则:

    1.QueryInterface返回的总是同一IUnknown指针。

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

    3.客户可以再次获取已经拥有的接口。

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

    5.若能从某个接口获取某特定接口,那么可以从任意接口都将可以获取此接口。



    QueryInterface定义了组件:

          QueryInterface是COM最为重要的部分,因为一个组件实际上就是由QueryInterface定义了,组件所支持的接口集就是QueryInterface能够为之返回接口指针的那些接口。

    这是由QueryInterface的实现决定的,而不是由实现组件的C++类决定的。

      客户不知道QueryInterface的实现,他将无法知道一个组件所支持的所有接口。   客户了解组件所支持接口的唯一方法是进行查询。

       COM类似于在某次社交聚会上同某人会面,而与对他们进行工作面试有很大不同,当进行工作面试时,被试者将提交一份介绍他情况的个人简历。这份简历类似于c++类的定义。而社交聚会上会面时,没有人会给对方提供个人简历。为了了解情况,必须询问。   这一点类似于COM组件。



    新版本的处理:

    Com中,接口是不会发生改变的,当组件发布一个接口并被某个客户使用之后,此接口将绝不会发生任何变化,而将永远保持不变。

    每一个接口都有一个唯一的接口标识符IID,  一般情况下,我们不会改变接口,而可以建立一个新接口并为之指定一个新的IID。

    当QueryInterface 接收到对老IID  的查询时,他将返回老接口,   而当他收到对新的IID的查询时,他将返回新的接口。   

    对QueryInterface 而言, 一个IID 就是一个接口。


    新的接口可以继承老接口,他也可以同老接口完全不同。  由于老接口仍然保持不变,已有客户的运行将不会收到任何影响。

    新客户可以自行决定是使用老接口还是新接口,因为他可以自由决定到底查询那个接口。


    接口的IID  据定了它的版本,当客户获取某个接口时,由于不同版本的接口实际上是不同的接口,他们各自具有不同的ID,因此客户仍能取得正确的版本的接口。


    我们何时需要建立一个新版本?

    当改变下列条件中的任何一个时,就应该给新街口指定新的id。

    1、接口中函数的数目;

    2、接口中函数的顺序;

    3、某个函数的参数;

    4.、某个函数参数的顺序;

    5、某个函数参数的类型;

    6、函数可能的返回值;

    7、函数返回值的类型;

    8、函数参数的含义;

    9、接口中函数的含义。


       只要是所做的修改会导致已有客户的正常运行,就需要接口指定新的ID。




    2013.8.4

    jofranks 于南昌



  • 相关阅读:
    简化单例模式
    static
    单例模式之懒汉模式
    Car race game
    poj-2403
    poj-2612
    poj-1833
    poj--2782
    poj--2608
    poj--3086
  • 原文地址:https://www.cnblogs.com/riskyer/p/3237005.html
Copyright © 2011-2022 走看看