我正在看《COM原理与应用》,其中第三章的例子(有关聚合部分的例子),看不明白,m_pUnknownInner->QueryInterface(iid, ppv)查询IID_SomeInterface时调用m_pUnknownInner-》QueryInterfacek(iid, ppv) 却是COMA的CA::NondelegationQueryInterface(const IID& iid, void **ppv)而不是HRESULT CA::QueryInterface(const IID& iid, void **ppv),请高手指点不胜感激!!!

解决方案 »

  1.   

    更正:
    我正在看《COM原理与应用》,其中第三章的例子(有关聚合部分的例子),看不明白,在CB::QueryInterface中查询IID_SomeInterface时调用m_pUnknownInner-》QueryInterfacek(iid, ppv) 却是COMA的CA::NondelegationQueryInterface(const IID& iid, void **ppv)而不是HRESULT CA::QueryInterface(const IID& iid, void **ppv),请高手指点不胜感激!!!
      

  2.   

    m_pUnknownInner是个非委派版本的IUnknown,在二进制上它实际上就是组件的INondelegationUnknown接口,而不是正常的IUnkonwn。
    来看看CFactory::CreateInstance()的伪代码。
    CFactory::CreateInstance(IUnknown * pUnkOuter, REFIID riid,void ** ppvObject)
    {
      ...
      if(pUnkOuter)
      {
        CObject *pObject = new CObject();
        INondelegationUnknown *pINondelegationUnknown;
        pObject->NondelegationQueryInterface(IID_INondelegationUnknown, reinterpret_cast<void **>(&pINondelegationUnknown));
        return ((IUnknown *)pINondelegationUnknown)->QueryInterface(riid, ppv);
      }
      ...
    }
    或者能帮你明白点什么吧。
      

  3.   

    sorry,我想我可能搞错了,最后一句应该是
    return ((IUnknown )(*pINondelegationUnknown)).QueryInterface(riid, ppv);
      

  4.   

    Sorry,刚才说错了。来看
    HRESULT __stdcall  CObject::NondelegatingQueryInterface(const IID& iid, void** ppv)
    {
      if (iid == IID_IUnknown)
      {
        IUnknown *pUnknown = reinterpret_cast<IUnknown*>,
    static_cast<INondelegatingUnknown*>(this));
        pUnknown->AddRef();
        *ppv = pUnknown;
        return S_OK;
      }
      else
      {
        *ppv = NULL ;
        return E_NOINTERFACE ;
      }
    }再来看
    HRESULT __stdcall CFactory::CreateInstance(IUnknown* pUnknownOuter,const IID& iid,void** ppv) 
    {
        if(pUnknownOuter && iid == IID_IUnknown)
        {
          CObject *pObject = new CObject();
          pObject->NondelegatingQueryInterface(iid, ppv);
        }
    }
      

  5.   

    阿信兄,你是说m_pUnknownInner是非委托的IUnknown指针,二进制上它是组件的INondelegationUnknown接口,而不是正常的IUnkonwn。这是通过C++实现的吗?我的C++学的不好,不是下面的定义是不是就是你所说的?class INondelegatingUnknown
    {
    public:
    virtual HRESULT  __stdcall  NondelegationQueryInterface(const IID& iid, void **ppv) = 0 ;
    virtual ULONG  __stdcall  NondelegatingAddRef() = 0; 
    virtual ULONG  __stdcall  NondelegationRelease() = 0;
    };class CA : public ISomeInterface, public INondelegatingUnknown
    {
    protected:
         ULONG           m_Ref;public:
         CA(IUnknown *pUnknownOuter);
         ~CA();public :
    // Delegating IUnknown
    virtual HRESULT   __stdcall  QueryInterface(const IID& iid, void **ppv) ;
    virtual ULONG   __stdcall  AddRef() ; 
    virtual ULONG   __stdcall  Release() ; // Nondelegating IUnknown
    virtual HRESULT   __stdcall  NondelegationQueryInterface(const IID& iid, void **ppv);
    virtual ULONG   __stdcall  NondelegatingAddRef();
    virtual ULONG   __stdcall  NondelegationRelease(); virtual HRESULT __stdcall SomeFunction( ) ; private :
    IUnknown  *m_pUnknownOuter;  // pointer to outer IUnknown
    };这样的类定义在二进制上是怎么样的,能讲讲吗?
      

  6.   

    对。
    不过由于INondelegationUnknown与IUnknown二进制兼容,CoCreateInstance的时候,把它强制转换成IUnknow指针了。
      

  7.   

    注意,在下面这个函数实现中,
    HRESULT __stdcall  CObject::NondelegatingQueryInterface(const IID& iid, void** ppv)
    {
      if (iid == IID_IUnknown)
      {
        IUnknown *pUnknown = reinterpret_cast<IUnknown*>,
    static_cast<INondelegatingUnknown*>(this));
        pUnknown->AddRef();
        *ppv = pUnknown;
        return S_OK;
      }
      else
      {
        *ppv = NULL ;
        return E_NOINTERFACE ;
      }
    }
    我还漏了点东西:
      if (iid == IID_IMyInterface)
      { 
        IMyInterface *pMyInterface = reinterpret_cast<IUnknown*>,
    static_cast<IUnknown*>(this));
        pMyInterface->AddRef();
        *ppv = pMyInterface;
      }这样一来,你在外部组件创建内部组建的时候,获得内部组件的非委派Unknown接口(注意,从这段代码可以看出,仅仅只有iid == IID_IUnknown的时候,才能获得非委派的接口,别的IID获得的是委派接口)。
    于是,在聚合的情况下,外部组件调用QueryInterface,内部组件通过非委派的INondelegatingUnknown::NondelegatingQueryInterface获得了委派的也就是真正的IUnknown接口,然后如果此时你继续调用QueryInterface,组件就把调用委派给外部组件,如此循环下去。
    要是组建没有被聚合呢?这时候组件继续调用非委派的INondelegatingUnknown::NondelegatingQueryInterface,获得委派的真正的IUnknown接口。
    再来看看这委派的IUnknown::QueInterface是如何实现的,你就明白好多了:
    HRESULT __stdcall  CObject::QueryInterface(const IID& iid, void** ppv)
    {
      if(m_pOuter) return m_pOuter->QueryInterface(iid, ppv);
      else return NondelegatingQueryInterface(iid, ppv);
    }
      

  8.   

    还是写错,全面写一次吧:
    HRESULT __stdcall  CObject::NondelegatingQueryInterface(const IID& iid, void** ppv)
    {
      if (iid == IID_IUnknown)
      {
        IUnknown *pUnknown = reinterpret_cast<IUnknown*>,
    static_cast<INondelegatingUnknown*>(this));
        pUnknown->AddRef();
        *ppv = pUnknown;
        return S_OK;
      }
      if (iid == IID_IMyInterface)
      { 
        IMyInterface *pMyInterface = reinterpret_cast<IMyInterface*>(this));
        pMyInterface->AddRef();
        *ppv = pMyInterface;
      } else
      {
        *ppv = NULL ;
        return E_NOINTERFACE ;
      }
    }
    不会死循环的,你仔细想想就明白了,关键是NondelegatingQueryInterface对不同的IID获得了不同版本的Unknown接口。
    这样做还有一个微妙的地方就是,内部组件标识为IID_IUnknown的真正的IUnknown接口永远不可能获得(),避免了跟外部组件的IID_IUnknown冲突。它所获得的只不过是通过INondelegatingUnknown强制转换过来的IUnknown接口。
      

  9.   

    为什么我们聚合另一个组件,创建m_pInner的时候,一定要用CoCreateInstance(...IID_IUnknown...)的原因,用别的IID你会出错的,要是单套Unknown接口实现的话,你是可以通过任意一个IID,然后强制转换成IUnknown接口的。只有CoCreateInstance(...IID_IUnknown...)才能获得对象的非委派Unknown接口。