com聚合有关问题讨论

com聚合问题讨论
C/C++ code



 聚合技术问题讨论

两个com对象A和B,A被B聚合。

当然A也可以不被聚合,所以 与A相关有了2个接口,一个非委托,一个委托

非委托接口: INondelegatingUnknown

委托接口:ISomeInterface




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个接口,这样才能给其他人或者自己继续开发.

其中的一个函数:QueryInterface的实现,我有疑问:


CA::QueryInterface 是一个查询接口的函数, 其大致流程为:

1.如果为聚合指针不为空,则进行使用聚合对象查询
2.如果聚合指针为空,则进行非委托查询NondelegationQueryInteface

代码为:

HRESULT CA::QueryInterface(const IID& iid, void **ppv)
{
    if  ( m_pUnknownOuter != NULL )
        return m_pUnknownOuter->QueryInterface(iid, ppv);        //实际上会被聚合对象B调用!!!
    else
        return NondelegationQueryInterface(iid, ppv);            //非委托查询
}




问题出来了: 非委托查询函数,何苦 分2种情形?  看代码:



(class CA:public INondelegatingUnknown,ISomeInterface)



HRESULT CA::NondelegationQueryInterface(const IID& iid, void **ppv)
{
    if ( iid == IID_IUnknown )
    {
        *ppv = (INondelegatingUnknown *) this ;
        ((IUnknown *)(*ppv))->AddRef() ;        //1种
    } else if ( iid == IID_SomeInterface ) 
    {
        *ppv = (ISomeInterface *) this ;
        ((ISomeInterface *)(*ppv))->AddRef() ;        //2种
    } 
    else
    {
        *ppv = NULL;
        return E_NOINTERFACE ;
    }
    return S_OK;
}

何苦非两种?










3. 



工厂类中的 中的m_ref到底有什么用?



为什么在DllGetClassObject 中创建工厂对象后, 立即查询接口,殊不知查询接口的代码很奇怪?(为什么说其诡异, 原因是:

尽管你有了工厂对象,但是 你没有创建com对象A啊, 增加次数m_ref有什么用呢?)


extern "C" HRESULT __stdcall DllGetClassObject(const CLSID& clsid, const IID& iid, void **ppv)
{
    if (clsid == CLSID_CompA) {
        
        CAFactory *pFactory = new CAFactory;        //只有工厂对象,没有com对象!!!
        
        if (pFactory == NULL) {
            return E_OUTOFMEMORY ;
        }
        
        HRESULT result = pFactory->QueryInterface(iid, ppv);        //开始查询接口,都没有com对象,查了作甚?

        return result;
    } else {
        return CLASS_E_CLASSNOTAVAILABLE;
    }
}



class CAFactory : public IClassFactory
{
   protected:
      ULONG           m_Ref;                //look here

  .....................
      //IUnknown members
      HRESULT __stdcall QueryInterface(const IID& iid, void **ppv);
      ULONG   __stdcall AddRef();
      ULONG   __stdcall Release();

};

以下是CAFactory::QueryInterface的代码:


HRESULT  CAFactory::QueryInterface(const IID& iid, void **ppv)
{
    if ( iid == IID_IUnknown )
    {
        *ppv = (IUnknown *) this ;
        ((IUnknown *)(*ppv))->AddRef() ;        //增加了m_ref的次数,有什么用呢?无用啊
    } else if ( iid == IID_IClassFactory) 
    {
        *ppv = (IClassFactory *) this ;
        ((IClassFactory *)(*ppv))->AddRef() ;        //同理这里也是
    } 
    else
    {
        *ppv = NULL;
        return E_NOINTERFACE ;
    }
    return S_OK;
}




以上代码 来自 com原理与应用







------解决方案--------------------
QueryInterface//开始查询接口,都没有com对象,查了作甚?
com对象可以在 QueryInterface时创建


增加了m_ref的次数,有什么用呢?无用啊

引用计数是COM基础的概念, 返回接口的指针, 就应该为该接口做保留, 否则工厂释放后, 接口就没了
前面的问题也是一样的道理
------解决方案--------------------
潘爱民写这本书的时候感觉不怎么懂com,反正我是翻了几页实在看不下去

找些国外的书和文章,东拼西凑下,然后自己做做实验,典型的中国式论文