要說明這個問題,首先我說下彙總介面的使用,藉助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()
HRESULT FinalConstruct()
...{
HRESULT hr = S_OK;
// 2.我們一般是在FinalConstruct裡面做彙總介面的建立
hr = CoCreateInstance(CLSID_EXAMPLE,
GetControllingUnknown(),
CLSCTX_ALL,
IID_IUnknown,
(void**)&m_spUnk);
return hr;
}
HRESULT FinalRelease()
...{
// 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~