描述:
最近在看潘爱民写的《com的原理和应用》,看到第四章关于com的聚合的例子不是很明白
。例子中有两个类CompB 和CompA. 其中Comp聚合了CompA.CompA实现了ISomeInterface和
INondelegatingUnknown, ISomeInterface继承了IUnkown.
其中INondelegatingUnknown的申明如下:
class INondelegatingUnknown
{
public:
virtual HRESULT __stdcall NondelegationQueryInterface(const IID& iid, void
**ppv) = 0 ;
virtual ULONG __stdcall NondelegatingAddRef() = 0;
virtual ULONG __stdcall NondelegationRelease() = 0;
};
类CompB的类厂在创建CompB的实例的时候,调用CoCreateInstance方法(CLSID_CompA, pU
nknownOuter, CLSCTX_INPROC_SERVER, IID_IUnknown, (void **)& m_pUnknownInner)来
创建类CompA的实例。这个方法又间接调用了类厂CAFactory的CreateInstance的函数,函
数的定义如下。
HRESULT CAFactory::CreateInstance(IUnknown *pUnknownOuter,
const IID& iid, void **ppv)
{
HRESULT hr;
// iid must be IID_IUnknown for aggregating
if ( ( pUnknownOuter != NULL ) && ( iid != IID_IUnknown ) )
{
return CLASS_E_NOAGGREGATION;
}
*ppv=NULL;
hr=E_OUTOFMEMORY;
//Create the object passing function to notify on destruction.
CA *pObj=new CA (pUnknownOuter);
if (NULL==pObj)
return hr;
//Obtain the first interface pointer (which does an AddRef)
hr = pObj->NondelegationQueryInterface(iid, ppv);
if (hr != S_OK) {
//Kill the object if initial creation or FInit failed.
g_CompANumber --; // Reference count g_CompANumber be added in constructor
delete pObj;
}
return hr;
}
在这个函数里面,当类A的实例生成之后,调用了NondelegationQueryInterface函数查询
IID_IUnknown接口
HRESULT CA::NondelegationQueryInterface(const IID& iid, void **ppv)
{
if ( iid == IID_IUnknown )
{
*ppv = (INondelegatingUnknown *) this ;
((IUnknown *)(*ppv))->AddRef() ; <---- Here is my question
} else if ( iid == IID_SomeInterface )
{
*ppv = (ISomeInterface *) this ;
((ISomeInterface *)(*ppv))->AddRef() ;
}
else
{
*ppv = NULL;
return E_NOINTERFACE ;
}
return S_OK;
}
然后发现((IUnknown *)(*ppv))->AddRef() 这里实际调用了NondelegatingAddRef()而不
是AddRef方法(我用Visual Studio 2005跟踪调试). 不知道为什么会这样, 有没有熟悉
这本书的人或者com的人能够解释一下。
解决方案1:
INondelegatingUnknown跟IUnknown是具有相同内存结构的虚拟函数表
在组件不被聚合的时候调用的是INondelegatingUnknown的函数
up
解决方案3:INondelegatingUnknown 是从IUnknown派生的吗?它实现了AddRef吗?如果实现了,调用了NondelegatingAddRef?
解决方案4: 这是由多态决定的。估计你的A代码中INondelegatingUnknown是放在前面的。
你应该把ISomeInterface放在前面。这样你调用addref就不会发生这种情况。
---------
//Obtain the first interface pointer (which does an AddRef)
hr = pObj->NondelegationQueryInterface(iid, ppv);
if (hr != S_OK) {
---------这就是就是访问第一个继承的接口,实际上,他误认为你的INondelegatingUnknown为ISomeInterface。
一家之言。