上一页 1 2 3 4 5 6 7 8 9 10 下一页 五.COM_INTERFACE_ENTRY_AGGREGATE(iid, punk)
这一节中将介绍ATL中用于聚集对象的宏。聚集对象的概念请参阅其它参考书。 现在先看一看这个宏的典型用法:
class CAgg : public IDispatchImpl< IAgg, &IID_IAgg, &LIBID_AGGREGLib >, public ISupportErrorInfo, public CComObjectRoot, public CComCoClass< CAgg,&CLSID_CAgg > { ..... }; | CAgg是一个聚集类,它的实现与一般的ATL组件没有区别,只是注意在它的类定义中不要加入DECLARE_NO_AGGREGATABLE.
class COuter : public CChainBase, public IDispatchImpl< IOuter, &IID_IOuter, &LIBID_COMMAPLib >, public CComCoClass< COuter,&CLSID_COuter > { HRESULT FinalConstruct(); void FinalRelease();
BEGIN_COM_MAP(COuter) COM_INTERFACE_ENTRY_AGGREGATE(IID_IAgg, m_pUnkAgg.p) END_COM_MAP()
DECLARE_GET_CONTROLLING_UNKNOWN()
CComPtr< IUnknown > m_pUnkAgg; }; | COuter包含了聚合组件CAgg,它包含了几个不同之处:
(1)加入了COM_INTERFACE_ENTRY_AGGREGATE(IID_IAgg, m_pUnkAgg.p)宏。
#define COM_INTERFACE_ENTRY_AGGREGATE(iid, punk)\ {&iid,\ (DWORD)offsetof(_ComMapClass, punk),\ _Delegate}, | offsetof我们在上一节中已经见过,可以猜到它求的就是punk在类中的位置。也就是m_pUnkAgg在COuter中的位置。
(2)加入了宏DECLARE_GET_CONTROLLING_UNKNOWN(),其定义为:
#define DECLARE_GET_CONTROLLING_UNKNOWN() public:\ virtual IUnknown* GetControllingUnknown() {return GetUnknown();} | 我们也没必要继续深究下去,仅从字面意思就可以看出这个函数将返回组件的IUnknown 指针。
(3)在COuter中加入一个成员变量:CComPtr< IUnknown > m_pUnkAgg; m_pUnkAgg将用于获得被聚集组件的IUnknown指针。
(4)重载了FinalConstruct,FinalRelease
HRESULT COuter::FinalConstruct() { IUnknown* pUnkOuter = GetControllingUnknown(); HRESULT hRes = CoCreateInstance(CLSID_CAgg, pUnkOuter, CLSCTX_ALL, IID_IUnknown, (void**)&m_pUnkAgg); return hRes; }
void COuter::FinalRelease() { m_pUnkAgg.Release(); ..... } | 当创建组件COuter后将会调用FinalConstruct,所以会在这里创建聚集组件。原则上聚集组件可以仅在需要的时候才创建,但也可以随着包含它的组件一起创建。聚集组件的创建没什么特别之处,只是要注意它将查询IUnknown指针,并返回给m_pUnkAgg.外部组件将通过m_pUnkAgg操作聚集组件。另外注意到使用pUnkOuter作为CoCreateInstance的参数,这将导致创建CComAggObject< COuter >对象,内部包含一个CComContainedObject的包含对象。与上一节中的CComCachedTearOff<>类似,CComAggObject< COuter >也不是从COuter派生的,所以真正的组件对象不是CComAggObject< COuter >对象,而是它内部包含的CComContainedObject< COuter >对象。同样pUnkOuter得到的将是CComAggObject<>的IUnknown指针,也同样调用它的QueryInterface会转而调用CComContainedObject的_InternalQueryInterface函数(呵呵,现在可都还是我猜的,看我猜的对不对吧)
运行pOuter->QueryInterface(IID_IAgg, (void **)&pAgg1)
函数堆栈一:
9.ATL::AtlInternalQueryInterface(...) 8.ATL::CComObjectRootBase::InternalQueryInterface(...) 7.CAgg::_InternalQueryInterface(...) 6.ATL::CComAggObject< CAgg >::QueryInterface(...) 5.ATL::CComObjectRootBase::_Delegate(...) 4.ATL::AtlInternalQueryInterface(...) 3.ATL::CComObjectRootBase::InternalQueryInterface(...) 2.COuter::_InternalQueryInterface(...) 1.ATL::CComObject< COuter >::QueryInterface(...) | 解释:
1-5:这几步函数调用我们已经见了很多次了,因为在这个宏定义使用了_Delegate,所以将调用CComObjectRootBase::_Delegate(...).
static HRESULT _Delegate(void* pv,REFIID iid,void** ppvObject,DWORD dw) { HRESULT hRes = E_NOINTERFACE; IUnknown* p = *(IUnknown**)((DWORD)pv + dw); if (p != NULL) hRes = p->QueryInterface(iid, ppvObject); return hRes; } | 第二句话的含义我们在上一节中已经见过了,最后的结果p=COuter::m_pUnkAgg.
6:正如我们刚才所料,现在调用的是CComAggObject< CAgg >::QueryInterface()
STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject) { //如果查询的是IUnknown,则.... else hRes = m_contained._InternalQueryInterface(iid, ppvObject); return hRes; } | 也正如我们所料,将交给它的包含对象去做.(这段代码在上一节好象也见过是吧,呵呵) 7-9:同上一节一样,将交给CAgg::_InternalQueryInterface(...),剩下的工作将由CAgg完成了。最后返回的指针实际上将是CComContainedObject< CAgg >组件的接口指针。
运行pAgg1->QueryInterface(IID_IAgg, (void **)&pAgg2)
函数堆栈二:
9.CAgg::_InternalQueryInterface(...) 8.ATL::CComAggObject< CAgg >::QueryInterface(...) 7.ATL::CComObjectRootBase::_Delegate(...) 6.ATL::AtlInternalQueryInterface(...) 5.ATL::CComObjectRootBase::InternalQueryInterface(...) 4.COuter::_InternalQueryInterface(...) 3.ATL::CComObject< COuter >::QueryInterface(...) 2.ATL::CComObjectRootBase::OuterQueryInterface(...) 1.ATL::CComContainedObject< CAgg >::QueryInterface(...) | 解释:
1-9:浏览整个堆栈,与我们上一节所见的堆栈二太相近了,这是因为都是使用了包含对象。包含对象起了个代理的作用,他先把查询交给外部对象(COuter)去做(第1,2步), 当外部对象发现要查询的是聚集组件的接口时(IAgg),就会再把查询交还给它保留的聚集组件的指针(m_pUnkAgg,第7步中,注意这不是真正的聚集组件),m_pUnkAgg再把查询交给包含对象(第8步中),包含对象再把查询交给真正实现接口的类CAgg(第9步). 若外部对象发现要查询的是外部组件的接口时,那就很简单了,直接查询就行了。这样就防止了外部组件与聚集组件查询操作的不一致性。唉,真个过程真麻烦,不过还好,与上一节的宏很类似。相关的源码可参看上一节。
上一页 1 2 3 4 5 6 7 8 9 10 下一页 |