ATL接口方法获取一个接口指针参数后,如何将此接口指针转变为C++对象指针?对于ATL对象,可以直接取得m_pCPPObj变量,而接口指针却不能。所以,需要提供一种途径,从ATL接口指针获取ATL组件的m_pCPPObj变量值。
我们的设计是,为每个ATL组件提供一个基接口ICPPObjSeeker,实现对绑定C++对象指针(即m_pCPPObj)的查询方法HandleCPPObj。任意ATL接口都从该基接口派生,都可以调用HandleCPPObj方法。
在前文就生命周期管理进行讨论时,曾提到这样一种情况:客户创建了一个组件,然后送交集合型组件管理。在集合型组件获取外部创建的组件的同时,需要:
l 取得后者的C++对象指针。集合型组件对元素组件管理的实质是通过集合型C++对象对元素的C++对象进行管理,而集合型ATL对象和元素ATL对象之间并没有直接联系
l 修改新加入元素组件的维护标识
因此,我们为ICPPObjSeeker接口添加PostCPPObj方法,用于实现以上功能。
ICPPObjSeeker接口idl定义如下所示,因为ICPPObjSeeker接口和HandleCPPObj、PostCPPObj方法实际上都应用于内部,所以使用“hidden”属性对外隐藏:
[
object,
uuid(1E9F7F79-936D-4680-9F8E-34A7DCCFF818),
dual,
hidden,
helpstring("ICPPObjSeeker Interface"),
pointer_default(unique)
]
interface ICPPObjSeeker : IDispatch
{
[id(1), helpstring("取得C++对象的指针"), hidden]
HRESULT HandleCPPObj([out, retval] long* pCPPObj);
[id(2), helpstring("取得C++对象的指针,客户程序不再负责对C++对象生命周期的维护"), hidden]
HRESULT PostCPPObj([out, retval] long* pCPPObj);
};
ICPPObjSeeker接口的方法可以放在CCPP2ATLTemplateBase模板基类中统一实现:
template <class T>
class CCPP2ATLTemplateBase :
{
……
/**********************************************************
HandleCPPObj函数,由ICPPObjSeeker接口定义,
负责取得ATL接口中的C++对象指针
**********************************************************/
STDMETHODIMP HandleCPPObj(long *pCPPObj)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState())
*pCPPObj = (long)m_pCPPObj;
return S_OK;
}
/**********************************************************
PostCPPObj函数,由ICPPObjSeeker接口定义,
负责取得ATL接口中的C++对象指针,
同时标记对象为内部维护,客户不再负责对象的生命周期管理
**********************************************************/
STDMETHODIMP PostCPPObj(long *pCPPObj)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState())
*pCPPObj = (long)m_pCPPObj;
if (m_bInnerManage == FALSE) {
m_bInnerManage = TRUE;
m_pCPPObj->m_pAssociATLUnk = this;
m_pCPPObj->m_pAssociATLUnk->AddRef();
}
return S_OK;
}
};
现在,所有的接口都不再直接从IDispatch派生,而改从ICPPObjSeeker派生,因此,IDispatch的实现也应该在实现ICPPObjSeeker接口的同一级或下级中提供。为了包容IDispatch,我们将ATL模板基类稍作改动:
template <class T, class Q, const IID* piid, const GUID* plibid = &CComModule::m_libid>
class ATL_NO_VTABLE CCPP2ATLTemplateBase :
public IDispatchImpl<Q, piid, plibid>
{
……
};