我正在看《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),请高手指点不胜感激!!!
我正在看《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),请高手指点不胜感激!!!
来看看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);
}
...
}
或者能帮你明白点什么吧。
return ((IUnknown )(*pINondelegationUnknown)).QueryInterface(riid, ppv);
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);
}
}
{
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
};这样的类定义在二进制上是怎么样的,能讲讲吗?
不过由于INondelegationUnknown与IUnknown二进制兼容,CoCreateInstance的时候,把它强制转换成IUnknow指针了。
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);
}
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接口。