组件聚合
发布时间:2020-12-13 20:37:28 所属栏目:百科 来源:网络整理
导读:对于HRESULT CoCreateInstance(REFCLSID rclsid,LPUNKNOWN pUnkOuter = NULL,DWORD dwClsContext = CLSCTX_ALL) throw(), 其中的 pUnkOuter决定所创造的组件是独立的还是聚合的。 CoCreateInstance | | pUnkOuter == NULL -----yes----- "new " CComObject C
对于HRESULT CoCreateInstance(REFCLSID rclsid,LPUNKNOWN
pUnkOuter = NULL,DWORD dwClsContext = CLSCTX_ALL) throw(), 其中的
pUnkOuter决定所创造的组件是独立的还是聚合的。 CoCreateInstance | | pUnkOuter == NULL -----yes-----> "new " CComObject <CClass> | no | "new " CComAggObject <CClass> 这里的 "new ",其实就是CComCreator.CreateInstance(pv,riid,ppv); 其中的pv = pUnkOuter ;
template
<
class
T1
>
class CComCreator { public : static HRESULTWINAPICreateInstance( void * pv,REFIIDriid,LPVOID * ppv) { ATLASSERT(ppv != NULL); if (ppv == NULL) return E_POINTER; * ppv = NULL; HRESULThRes = E_OUTOFMEMORY; T1 * p = NULL; ATLTRY(p = new T1(pv)) if (p != NULL) { p -> SetVoid(pv); p -> InternalFinalConstructAddRef(); hRes = p -> FinalConstruct(); if (SUCCEEDED(hRes)) hRes = p -> _AtlFinalConstruct(); p -> InternalFinalConstructRelease(); if (hRes == S_OK) hRes = p -> QueryInterface(riid,ppv); if (hRes != S_OK) deletep; } return hRes; } }; 这个过程对于独立或聚合来说,没有什么大的区别。 关于组件聚合,需要分两方面讨论: 1。 聚合别的组件(外部)
class
ATL_NO_VTABLECComplexMath:
public CComObjectRootEx < CComSingleThreadModel > , public CComCoClass < CComplexMath, & CLSID_ComplexMath > , public IDispatchImpl < IComplexMath, & IID_IComplexMath, & LIBID_COMPLEXCALCULATORLib > { public : CComplexMath() { } DECLARE_REGISTRY_RESOURCEID(IDR_COMPLEXMATH) DECLARE_PROTECT_FINAL_CONSTRUCT() BEGIN_COM_MAP(CComplexMath) COM_INTERFACE_ENTRY(IComplexMath) COM_INTERFACE_ENTRY_AGGREGATE(IID_ISimpleMath,ptrUnk) <=== 增加要暴露的内部组件接口,到内部组件IUnknown接口的映射 COM_INTERFACE_ENTRY(IDispatch) END_COM_MAP() // IComplexMath public : STDMETHOD(Divide)( /* [in] */ int x, /* [in] */ int y, /* [out,retval] */ int * z); // Aggregation:Addthecontrollingmacro,finalconstructandfinalrelease DECLARE_GET_CONTROLLING_UNKNOWN() <=== 获取外部IUnknown接口指针 IUnknown*ptrUnk;<=== 内部组件的IUnknown接口指针 HRESULTFinalConstruct() { return CoCreateInstance(CLSID_SimpleMath,GetControllingUnknown(),CLSCTX_ALL,IID_IUnknown,( void ** ) & ptrUnk); <=== 创建内部组件(引入pUnkOuter),并获得内部组件的IUnknown接口指针ptrUnk } void FinalRelease() { ptrUnk ->Release();<=== 释放内部组件的IUnknown接口指针 } // End }; 聚合接口映射宏: COM_INTERFACE_ENTRY_AGGREGATE (IID_ISimpleMath,ptrUnk) 展开为: #define COM_INTERFACE_ENTRY_AGGREGATE(iid,punk)/ {&iid,/ (DWORD_PTR)offsetof(_ComMapClass,punk),/ // dw中存储的是内部对象接口指针在外部对象中的偏移量 _Delegate}, ATL使用_Delegate来支持聚合。
static
HRESULTWINAPI_Delegate(
void
*
pv,REFIIDiid,
void
**
ppvObject,DWORD_PTRdw)
{ HRESULThRes = E_NOINTERFACE; IUnknown * p = * (IUnknown ** )((DWORD_PTR)pv + dw); // 通过偏移量得到内部接口指针 if (p != NULL) hRes = p -> QueryInterface(iid,ppvObject); // 查询得到所要求的内部接口指针 return hRes; } ATLINLINEATLAPIAtlInternalQueryInterface( void * pThis, const _ATL_INTMAP_ENTRY * pEntries, void ** ppvObject) { ATLASSERT(pThis != NULL); // Firstentryinthecommapshouldbeasimplemapentry ATLASSERT(pEntries -> pFunc == _ATL_SIMPLEMAPENTRY); if (ppvObject == NULL) return E_POINTER; * ppvObject = NULL; if (InlineIsEqualUnknown(iid)) // usefirstinterface { IUnknown * pUnk = (IUnknown * )((INT_PTR)pThis + pEntries -> dw); pUnk -> AddRef(); * ppvObject = pUnk; return S_OK; } while (pEntries -> pFunc != NULL) { BOOLbBlind = (pEntries -> piid == NULL); if (bBlind||InlineIsEqualGUID( * (pEntries -> piid),iid)) { if (pEntries -> pFunc == _ATL_SIMPLEMAPENTRY) // offset { ATLASSERT( ! bBlind); IUnknown * pUnk = (IUnknown * )((INT_PTR)pThis + pEntries -> dw); pUnk -> AddRef(); * ppvObject = pUnk; return S_OK; } else // actualfunctioncall { HRESULThRes = pEntries -> pFunc(pThis, <== 使用_Delegate来支持聚合。 iid,ppvObject,pEntries -> dw); if (hRes == S_OK||( ! bBlind && FAILED(hRes))) return hRes; } } pEntries ++ ; } return E_NOINTERFACE; } 由此可见,接口映射表就像一个“路由器”---将不同的接口请求转发到外部或内部组件。 BEGIN_COM_MAP(CComplexMath) COM_INTERFACE_ENTRY(IComplexMath) COM_INTERFACE_ENTRY_AGGREGATE (IID_ISimpleMath,ptrUnk) <=== 增加要暴露的内部组件接口,到内部组件IUnknown接口的映射 COM_INTERFACE_ENTRY(IDispatch) END_COM_MAP() 2。被聚合的组件(内部) 一个组件以被聚合形式存在时,最关键在于---pUnkOuter 的引入(p = new T1(pv))。 被聚合的组件实现了两套:AddRef,Release 和 QueryInterface。 一套用于内部控制; 一套用于外部控制-- 通过pUnkOuter;
template
<
class
contained
>
class CComAggObject: public IUnknown, public CComObjectRootEx < contained::_ThreadModel::ThreadModelNoCS > { public : .............. STDMETHOD_(ULONG,AddRef)(){ return InternalAddRef();} // 内部 STDMETHOD_(ULONG,Release)() // 内部 { ULONGl = InternalRelease(); if (l == 0 ) delete this ; return l; } STDMETHOD(QueryInterface)(REFIIDiid, void ** ppvObject) // 内部 { ATLASSERT(ppvObject != NULL); if (ppvObject == NULL) return E_POINTER; * ppvObject = NULL; HRESULThRes = S_OK; if (InlineIsEqualUnknown(iid)) { * ppvObject = ( void * )(IUnknown * ) this ; AddRef(); ......... } else hRes = m_contained._InternalQueryInterface(iid,ppvObject); // return hRes; } ... CComContainedObject < contained > m_contained; }; template < class Base > // BasemustbederivedfromCComObjectRoot class CComContainedObject: public Base { public : typedefBase_BaseClass; CComContainedObject( void * pv){m_pOuterUnknown = (IUnknown * )pv;} #ifdef_ATL_DEBUG_INTERFACES ~ CComContainedObject() { _AtlDebugInterfacesModule.DeleteNonAddRefThunk(_GetRawUnknown()); _AtlDebugInterfacesModule.DeleteNonAddRefThunk(m_pOuterUnknown); } #endif STDMETHOD_(ULONG,AddRef)(){ return OuterAddRef();} // 外部 STDMETHOD_(ULONG,Release)(){ return OuterRelease();} // 外部 STDMETHOD(QueryInterface)(REFIIDiid, void ** ppvObject) // 外部 { return OuterQueryInterface(iid,ppvObject); } template < class Q > HRESULTSTDMETHODCALLTYPEQueryInterface(Q ** pp) { return QueryInterface(__uuidof(Q),( void ** )pp); } // GetControllingUnknownmaybevirtualiftheBaseclasshasdeclared // DECLARE_GET_CONTROLLING_UNKNOWN() IUnknown * GetControllingUnknown() { #ifdef_ATL_DEBUG_INTERFACES IUnknown * p; _AtlDebugInterfacesModule.AddNonAddRefThunk(m_pOuterUnknown,_T( " CComContainedObject " ), & p); return p; #else return m_pOuterUnknown; #endif } }; BEGIN_COM_MAP(CAdvance) (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |