要说明这个问题,首先我说下聚合接口的使用,借助ATL我们是这么用的:
/**/
//////////////////////////////////////////////////////////////////////////
// 例子
class CExample
// :......
... {
BEGIN_COM_MAP(CExample)
//......
//1.在接口映射表中加上要聚合出去的接口,并指定QI时
// 得到的接口指针
COM_INTERFACE_ENTRY_AGGREGATE(IID_IEXAMPLE,m_spUnk);
END_COM_MAP()
//......
DECLARE_GET_CONTROLLING_UNKNOWN()
DECLARE_PROTECT_FINAL_CONSTRUCT()
HRESULTFinalConstruct()
...{
HRESULThr=S_OK;
//2.我们一般是在FinalConstruct里面做聚合接口的创建
hr=CoCreateInstance(CLSID_EXAMPLE,
GetControllingUnknown(),
CLSCTX_ALL,
IID_IUnknown,
(void**)&m_spUnk);
returnhr;
}
HRESULTFinalRelease()
...{
//3.我们一般是在FinalRelease里面做聚合接口的释放
m_spUnk.Release();
}
public:
CComPtr<IUnknown>m_spUnk;
} ;
// 例子结束
/**/ //////////////////////////////////////////////////////////////////////////
// 例子
class CExample
// :......
... {
BEGIN_COM_MAP(CExample)
//......
//1.在接口映射表中加上要聚合出去的接口,并指定QI时
// 得到的接口指针
COM_INTERFACE_ENTRY_AGGREGATE(IID_IEXAMPLE,m_spUnk);
END_COM_MAP()
//......
DECLARE_GET_CONTROLLING_UNKNOWN()
DECLARE_PROTECT_FINAL_CONSTRUCT()
HRESULTFinalConstruct()
...{
HRESULThr=S_OK;
//2.我们一般是在FinalConstruct里面做聚合接口的创建
hr=CoCreateInstance(CLSID_EXAMPLE,
GetControllingUnknown(),
CLSCTX_ALL,
IID_IUnknown,
(void**)&m_spUnk);
returnhr;
}
HRESULTFinalRelease()
...{
//3.我们一般是在FinalRelease里面做聚合接口的释放
m_spUnk.Release();
}
public:
CComPtr<IUnknown>m_spUnk;
} ;
// 例子结束
/**/ //////////////////////////////////////////////////////////////////////////
2. 我的问题
我们如果都按上面的方法自然不会有错,但是如果我们不想在FinalConstruct中实现呢?
我的做法是和FinalConstruct/FinalRelease对应的写了两个函数Init()/Uninit(),但是使用
后却发现了莫名奇妙的"服务器出现意外情况",在注释掉部分代码后发现,是因为我在不正确
的地方释放了m_spUnk!我是在Uninit()里面进行的m_spUnk.Release();这样为什么会有问题?
问题就出在:接口映射表中有用到了这个m_spUnk,且这个不会加引用计数,如果你在Uninit中
就释放了这个m_spUnk那么在组件要退出时,他也会运行在接口映射表,这时就会出现异常,因
为他所调用的m_spUnk已经在之前Release了。
3.解决
知道问题了就好办了,我就干脆不把m_spUnkRelease放回FinalRelease,当然要判断一下是否为
空,看来写每一行代码都要对他的作用明明白白才可以。
Good luck~
原文链接:https://www.f2er.com/javaschema/288086.html