最近在看潘爱民写的《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的人能够解释一下。
。例子中有两个类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的人能够解释一下。
---------
//Obtain the first interface pointer (which does an AddRef)
hr = pObj->NondelegationQueryInterface(iid, ppv);
if (hr != S_OK) {
---------这就是就是访问第一个继承的接口,实际上,他误认为你的INondelegatingUnknown为ISomeInterface。一家之言。
在组件不被聚合的时候调用的是INondelegatingUnknown的函数
INondelegatingUnknow的申明如下:class INondelegatingUnknown
{
public:
virtual HRESULT __stdcall NondelegationQueryInterface(const IID& iid, void **ppv) = 0 ;
virtual ULONG __stdcall NondelegatingAddRef() = 0;
virtual ULONG __stdcall NondelegationRelease() = 0;
};然后我修改了一下这个接口 NondelegatingAddRef()和 NondelegationRelease()的申明的顺序, 就是把NondelegationRelease放到NondelegationAddRef前面,发现这样的话,上面的代码
((IUnknown *)(*ppv))->AddRef() ;实际调用的就是NondelegationRelease()。 呵呵, 感觉有点和多继承下vptr和vtable在内存中的模型有关系。 看来我要把inside C++ object model 这本书翻出来好好看看了。