问题代码有一点长,但是对于明白聚合的高手来说很容易,只是一个聚合的例子。
先对您的眼说抱歉……… 解决问题必连开3帖(300分)酬谢。
有关COM聚合的问题。先贴出部分代码,大家看看。
//client.cpp
void trace(const char* msg) { cout << "Client: \t" << msg << endl ;}
//这时是为了显示输出是从哪个模块来的。
int main()
{
// Initialize COM Library
CoInitialize(NULL) ;

trace("Get interface IX from Component 1.") ;
IX* pIX = NULL ; 
HRESULT hr = ::CoCreateInstance(CLSID_Component1,  //这里是所请求的聚合对象
                                NULL, 
                                CLSCTX_INPROC_SERVER,
                                IID_IX, 
                                (void**)&pIX) ;
if (SUCCEEDED(hr))
{
trace("Succeeded creating component.") ;
                .........
        }
        ..........
CoUninitialize() ;

return 0 ;
}

解决方案 »

  1.   

    // cmpnt1.cpp-Component1 外部组件(聚合组件)的实现
    ......
    void trace(const char * msg){cout<<"Component 1:\t"<<msg<<endl;}class CA : public IX
            // public IY @N
    {
    public:
    // IUnknown
    virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv) ;
    virtual ULONG   __stdcall AddRef() ;
    virtual ULONG   __stdcall Release() ;

    // Interface IX
    virtual void __stdcall Fx() { cout << "Fx" << endl ;}

    /* @N Component1 aggregates instead of implementing interface IY.
    // Interface IY
    virtual void __stdcall Fy() { m_pIY->Fy() ;}
    */

    // Constructor
    CA() ;

    // Destructor
    ~CA() ;

    // Initialization function called by the class factory
    // to create the contained component
    HRESULT __stdcall Init() ;  // @Nprivate:
    // Reference count
    long m_cRef ;

    // Pointer to the aggregated component's IY interface
    // (We do not have to retain an IY pointer. However, we
    // can use it in QueryInterface.)
    IY* m_pIY ;                 // @N

    // Pointer to inner component's IUnknown
    IUnknown* m_pUnknownInner ; // @N
    } ;HRESULT __stdcall CA::Init()
    {
    // Get the pointer to the outer unknown.
    // Since this component is not aggregated, the outer unknown
    // is the same as the this pointer. 
    IUnknown* pUnknownOuter = this ;

    trace("Create inner component.") ;
    HRESULT hr =
    ::CoCreateInstance(CLSID_Component2,   
                       pUnknownOuter, // Outer component's IUnknown @N
                       CLSCTX_INPROC_SERVER,
                       IID_IUnknown,  // IUnknown when aggregating  @N
                       (void**)&m_pUnknownInner) ; 
    if (FAILED(hr))
    {
    trace("Could not create contained component.") ;
    return E_FAIL ;
    }

    // This call will increment the reference count on the outer component.
    trace("Get the IY interface from the inner component.") ;
    hr = m_pUnknownInner->QueryInterface(IID_IY, (void**)&m_pIY) ; //@N
    if (FAILED(hr))
    {
    trace("Inner component does not support interface IY.") ;
    m_pUnknownInner->Release() ;
    return E_FAIL ;
    }

    // We need to release the reference count added to the
    // outer component in the above call.  So call Release
    // on the pointer you passed to CoCreateInstance.
    pUnknownOuter->Release() ; //@N
    return S_OK ;
    }
    HRESULT __stdcall CFactory::CreateInstance(IUnknown* pUnknownOuter,
                                               const IID& iid,
                                               void** ppv) 
    {
    // Cannot aggregate
    if (pUnknownOuter != NULL)
    {
    return CLASS_E_NOAGGREGATION ;
    }

    // Create component.
    CA* pA = new CA ;
    if (pA == NULL)
    {
    return E_OUTOFMEMORY ;
    }

    // Initialize the component. @N
    HRESULT hr = pA->Init() ;
    if (FAILED(hr))
    {
    // Initialization failed. Delete component.
    pA->Release() ;
    return hr ;
    }

    // Get the requested interface.
    hr = pA->QueryInterface(iid, ppv) ;
    pA->Release() ;
    return hr ;   
    }
      

  2.   

    //Cmpnt2.cpp-Component2 内部组件(被聚合组件的实现)void trace(const char* msg) { cout << "Component 2:\t" << msg << endl ;}
    struct INondelegatingUnknown
    {
    virtual HRESULT __stdcall
    NondelegatingQueryInterface(const IID&, void**) = 0 ;
    virtual ULONG __stdcall NondelegatingAddRef() = 0 ;
    virtual ULONG __stdcall NondelegatingRelease() = 0 ;
    } ; //非委托IUnknown接口class CB : public IY,
               public INondelegatingUnknown
    {
    public:
    // Delegating IUnknown
    virtual HRESULT __stdcall
    QueryInterface(const IID& iid, void** ppv)
    {
    trace("Delegate QueryInterface.") ;
    return m_pUnknownOuter->QueryInterface(iid, ppv) ; 
    } virtual ULONG __stdcall AddRef() 
    {
    trace("Delegate AddRef.") ;
    return m_pUnknownOuter->AddRef() ; 
    } virtual ULONG __stdcall Release() 
    {
    trace("Delegate Release.") ;
    return m_pUnknownOuter->Release() ; 
    } // Nondelegating IUnknown
    virtual HRESULT __stdcall
    NondelegatingQueryInterface(const IID& iid, void** ppv) ;
    virtual ULONG   __stdcall NondelegatingAddRef() ;
    virtual ULONG   __stdcall NondelegatingRelease() ; // Interface IY
    virtual void __stdcall Fy() { cout << "Fy" << endl ;} // Constructor
    CB(IUnknown* m_pUnknownOuter) ; // Destructor
    ~CB() ;private:
    long m_cRef ;

    IUnknown* m_pUnknownOuter ;
    } ;HRESULT __stdcall CB::NondelegatingQueryInterface(const IID& iid,
                                                      void** ppv)

    if (iid == IID_IUnknown)
    {
    // !!! CAST IS VERY IMPORTANT !!!
    *ppv = static_cast<INondelegatingUnknown*>(this) ;  // @N
    }
    else if (iid == IID_IY)
    {
    *ppv = static_cast<IY*>(this) ;
    }
    else
    {
    *ppv = NULL ;
    return E_NOINTERFACE ;
    }
    reinterpret_cast<IUnknown*>(*ppv)->AddRef() ;
    return S_OK ;
    }ULONG __stdcall CB::NondelegatingAddRef()
    {
    return ::InterlockedIncrement(&m_cRef) ;
    }ULONG __stdcall CB::NondelegatingRelease() 
    {
    if (::InterlockedDecrement(&m_cRef) == 0)
    {
    delete this ;
    return 0 ;
    }
    return m_cRef ;
    }CB::CB(IUnknown* pUnknownOuter) 
    : m_cRef(1)

    ::InterlockedIncrement(&g_cComponents) ;  if (pUnknownOuter == NULL)
    {
    trace("Not aggregating; delegate to nondelegating IUnknown.") ;
    m_pUnknownOuter = reinterpret_cast<IUnknown*>
                      (static_cast<INondelegatingUnknown*>
                      (this)) ;
    }
    else
    {
    trace("Aggregating; delegate to outer IUnknown.") ;
    m_pUnknownOuter = pUnknownOuter ;
    }
    }
    HRESULT __stdcall CFactory::CreateInstance(IUnknown* pUnknownOuter,
                                       const IID& iid,
                                       void** ppv)
    {
    // Aggregate only if the requested iid is IID_IUnknown.
    if ((pUnknownOuter != NULL) && (iid != IID_IUnknown)) //@N
    {
    return CLASS_E_NOAGGREGATION ;
    }

    // Create component.
    CB* pB = new CB(pUnknownOuter) ; // @N
    if (pB == NULL)
    {
    return E_OUTOFMEMORY ;
    }
    // Get the requested interface.
    HRESULT hr = pB->NondelegatingQueryInterface(iid, ppv) ; //@N
    pB->NondelegatingRelease() ; 
    return hr ;   
    }
      

  3.   

    程序显示如下:
    Client:    Get interface IX from Component1.   
    Component 1:    Create inner component.
    Component 2:    Aggregating;delegate to outer IUnknown.
    Component 1:    Get the IY interface from the inner component.
    Component 2:    Delegate AddRef.
    Client:    Succeeded creating component.让我不明白的是:"Component 2:    Delegate AddRef."是从哪里出来的??
    你看,对于CA:: m_pUnknownInner  得到的是内部对象的非委托IUnknown指针(*ppv = static_cast<INondelegatingUnknown*>(this) ;)那么对于外部对象(聚合对象)来说,它应该不可能访问
    非委托IUnknown指针也就不可能调用
    virtual ULONG __stdcall AddRef() 
    {
    trace("Delegate AddRef.") ;
    return m_pUnknownOuter->AddRef() ; 
    }
    虽然在
    HRESULT __stdcall CB::NondelegatingQueryInterface(const IID& iid,
                                                      void** ppv)

    if (iid == IID_IUnknown)
    {
    // !!! CAST IS VERY IMPORTANT !!!
    *ppv = static_cast<INondelegatingUnknown*>(this) ;  // @N
    }
    else if (iid == IID_IY)
    {
    *ppv = static_cast<IY*>(this) ;
    }
    else
    {
    *ppv = NULL ;
    return E_NOINTERFACE ;
    }
    reinterpret_cast<IUnknown*>(*ppv)->AddRef() ;
    return S_OK ;
    }
    看这里:reinterpret_cast<IUnknown*>(*ppv)->AddRef() ;虽然把非委托IUnknown指针进行了转化,但是它也不可能变为委托针啊????。为什么,请大家指教。真的是因为这里么,这也是唯一的可能了。
      

  4.   

    这个问题,我知道,而且很清楚!告诉你吧,老兄!!首先,你必须得明白虚函数调用的机制,在虚函数表用,调用哪个函数,不是根据函数的名字来定的,而是根据函数在虚函数表的位置来定的。FOR EXAMPLEClass A
    {
         virtual func1();
         virtual func2();
         virtual func3();
    };Class B
    {
         virtual func4();
         virtual func5();
         virtual func6();
    };Class C:public A,public B
    {
          func1(){};
          func2(){};
          func3(){};
          func4(){};
          func5(){};
          func6(){};
    }main()
    {
        A * pA=new C();
        B * pB=(B *)A;
        B->func5();//notice!!!! func5 Not the B interface;
    }B->func5();调用的是A接口的func2()函数!明白了没?
      

  5.   

    这个我也知啊,可是正是因为我知才感到不明白啊,
    reinterpret_cast<IUnknown*>(*ppv)->AddRef() 调用的是
    ULONG __stdcall CB::NondelegatingAddRef()
    {
    return ::InterlockedIncrement(&m_cRef) ;
    }
    对吧。可是,你看显示的是什么?Component 2:    Delegate AddRef.
    这不是在 virtual ULONG __stdcall AddRef() 
    {
    trace("Delegate AddRef.") ;
    return m_pUnknownOuter->AddRef() ; 
    }
    为什么,请指教,
      

  6.   

    大错特错!在COM中,所有的接口都是派生于IUnknown的,那么在CB::NondelegatingQueryInterface中,能够得到*ppv的两个接口一个本身就是IUnknown,另一个则是IY,它是派生于IUnknown的,而你在CB的实现中实现了IUnknown的三个函数,也就是说在reinterpret_cast<IUnknown*>(*ppv)->AddRef() 中,实际上是调用
    virtual ULONG __stdcall AddRef() 
    {
    trace("Delegate AddRef.") ;
    return m_pUnknownOuter->AddRef() ; 
    }
    而至于NondelegatingQueryInterface,NondelegatingAddRef只有在创建对象的时候才会调用唯一的一次,其他的时候在被聚合对象上调用AddRef,Release,QueryInterface时都会转到外部对象上去,而只要调用一次NondelegatingAddRef,就能够保证在外部对象的生命周期内,被聚合对象始终都是存活的。你应该把外部对象的Release方法也贴出来,你应该能够在这个函数里面找到问题的答案
      

  7.   

    to golden_alvin(Alvin) ()
    "在COM中,所有的接口都是派生于IUnknown的",我认为不完会吧,看这里;
    struct INondelegatingUnknown
    {
    virtual HRESULT __stdcall
    NondelegatingQueryInterface(const IID&, void**) = 0 ;
    virtual ULONG __stdcall NondelegatingAddRef() = 0 ;
    virtual ULONG __stdcall NondelegatingRelease() = 0 ;
    } ; //非委托IUnknown接口
    “CB::NondelegatingQueryInterface中,能够得到*ppv的两个接口一个本身就是IUnknown”看这里:
    HRESULT __stdcall CB::NondelegatingQueryInterface(const IID& iid,
                                                      void** ppv)

    if (iid == IID_IUnknown)
    {
    // !!! CAST IS VERY IMPORTANT !!!
    *ppv = static_cast<INondelegatingUnknown*>(this) ;  // 得到的是非委托IUnknown
    }
    else if (iid == IID_IY)
    {
    *ppv = static_cast<IY*>(this) ;
    }
    else
    {
    *ppv = NULL ;
    return E_NOINTERFACE ;
    }
    reinterpret_cast<IUnknown*>(*ppv)->AddRef() ;//这里进行了转化,实际上目的是为了聚合,不聚合都可用,变了名字不变本性,它一定是调用CB::NondelegatingAddRef()不信你跟踪看看。to anyone:HELP ME,HELP ME~~~~~~
      

  8.   

    不知你是怎么得出这样的一段程序的,但是COM的精华就是接口,而所有的接口都来自IUnknown,否则即便你符合接口的思想,也仍然不是COM,因为微软的COM底层中,认为IUnknown是必备条件,所以你的程序永远不会被当作COM调用
    CoInitialize(NULL) ;

    trace("Get interface IX from Component 1.") ;
    IX* pIX = NULL ; 
    HRESULT hr = ::CoCreateInstance(CLSID_Component1,  //这里是所请求的聚合对象
      

  9.   

    CoInitialize(NULL) ;

    trace("Get interface IX from Component 1.") ;
    IX* pIX = NULL ; 
    HRESULT hr = ::CoCreateInstance(CLSID_Component1,  //这里是所请求的聚合对象
    这样的程序永远都是有问题的,因为你想使用COM的底层机制,却不愿遵守它的规则
    建议仔细研究一下COM理论,我想你一定是看了那本书上写了IX这样的接口,如果作者不想误人的话,一定会认真解释IX的作用以及其与IUnknown的关系
      

  10.   

    注意这里:
    HRESULT __stdcall CA::Init()中的
    hr = m_pUnknownInner->QueryInterface(IID_IY, (void**)&m_pIY) ;
    这里要调用class CB 的QueryInterface,而class CB的QueryInterface又调用了class CA的QueryInterface,只要你观察class CA的QueryInterface,就会发现如果查询的接口是IY的话,那么这个函数会直接调用class CB的NondelegatingQueryInterface,从而引起NondelegatingQueryInterface中的else if (iid == IID_IY)
    {
    *ppv = static_cast<IY*>(this) ;
    }
    被执行,这样*ppv就是IUnknow的VPTR,在它上面调用AddRef的时候当然会打印出那样一条语句
      

  11.   

    你说得没错,CB::NondelegatingAddRef()的确会被调用,因为在Init中创建对象的时候查询的是IUnknow,但是AddRef也会被调用的,你也可以跟踪一下
      

  12.   

    上面我说得好象不太对。
    你看这里hr = m_pUnknownInner->QueryInterface(IID_IY, (void**)&m_pIY);
    实际上调用的是CB::NodelegatingQueryIntercace,那么由于查询的是IY接口,那么
    else if (iid == IID_IY)
    {
    *ppv = static_cast<IY*>(this) ;
    }
    就必然会被执行到,这样就必然会调用到AddRef方法
      

  13.   

    HRESULT __stdcall CB::NondelegatingQueryInterface(const IID& iid,
                                                      void** ppv)

    if (iid == IID_IUnknown)
    {
    // !!! CAST IS VERY IMPORTANT !!!
    *ppv = static_cast<INondelegatingUnknown*>(this) ;  // @N
    }
    else if (iid == IID_IY)
    {
    *ppv = static_cast<IY*>(this) ; // 注意这一行
    }
    else
    {
    *ppv = NULL ;
    return E_NOINTERFACE ;
    }
    reinterpret_cast<IUnknown*>(*ppv)->AddRef() ;
    return S_OK ;
    }>让我不明白的是:"Component 2:    Delegate AddRef."是从哪里出来的??如果你跟踪代码,就会发现,经过 *ppv = static_cast<IY*>(this) ; 转换后,
    *ppv 这个指针已经开始指向 IY 了,而 IY 又是从 IUnknown 派生来的,
    所以 reinterpret_cast<IUnknown*>(*ppv)->AddRef() ; 肯定调用
    IUnknown版的AddRef()啦
      

  14.   

    谢了,大家,我明白了,呵,真开心啊,一个星期的问题原来是在这个小地方,由于我只是注意到
    if (iid == IID_IUnknown)
    {
    // !!! CAST IS VERY IMPORTANT !!!
    *ppv = static_cast<INondelegatingUnknown*>(this) ;  // @N
    }
    是调用的INondelegatingUnknown::ADDREF(),而没有看到当
    else if (iid == IID_IY)
    {
    *ppv = static_cast<IY*>(this) ; // 注意这一行
    }
    而IID_IY是从IUnknown来的,呵,好了,给分,
    谢谢
     brave_heart(intrepid)更加感谢 golden_alvin(Alvin)
      

  15.   

    不行啊,那一贴在http://expert.csdn.net/expert/Topicview2.asp?id=1750745
    请两位去那说句话,我才能给分,快啊~~~