精华区 [关闭][返回]

当前位置:网易精华区>>讨论区精华>>编程开发>>C/C++>>资料汇编----------藏经阁>>ATL接口映射宏详解>>ATL接口映射宏详解--(5)

主题:ATL接口映射宏详解--(5)
发信人: mrcloud()
整理人: kevintz(2000-08-24 02:02:26), 站内信件
发信人: lostall (鸟人+衰人+猪), 信区: COM_DCOM
标  题: ATL接口映射宏详解--(5)
发信站: 武汉白云黄鹤站 (Mon Apr  3 19:25:48 2000), 站内信件

五.COM_INTERFACE_ENTRY_AGGREGATE(iid, punk)    参ATL例程COMMAP


   这一节中将介绍ATL中用于聚集对象的宏。聚集对象的概念请参阅其它参考书

   现在先看一看这个宏的典型用法:
class CAgg :
        public IDispatchImpl,
        public ISupportErrorInfo,
        public CComObjectRoot,
        public CComCoClass
{
        .....
};
  CAgg是一个聚集类,它的实现与一般的ATL组件没有区别,只是注意在它的类定
义中不
要加入DECLARE_NO_AGGREGATABLE.
class COuter :
        public CChainBase,
        public IDispatchImpl,
        public CComCoClass
{
        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 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()
;}
  我们也必要继续深究下去,仅从字面意思就可以看出这个函数将返回组件的IU
nknown
  指针。
(3)在COuter中加入一个成员变量:CComPtr m_pUnkAgg;
   m_pUnkAgg将用于获得被聚集组件的IUnknown指针。
(4)重载了FinalConstruct,FinalRelease
  HRESULT COuter::FinalConstruct()
  {
        IUnknown* pUnkOuter = GetControllingUnknown();
        HRESULT hRes = CoCreateInstance(CLSID_CAgg, pUnkOuter,
                CLSCTX_INPROC_SERVER, IID_IUnknown, (void**)&m_pUnkAgg
);
        if (hRes != S_OK)
                return hRes;
        return S_OK;
  }
  void COuter::FinalRelease()
  {
        m_pUnkAgg.Release();
        .....
  }
  当创建组件COuter后将会调用FinalConstruct,所以会在这里创建聚集组件。
原则上
聚集组件可以仅在需要的时候才创建,但也可以随着包含它的组件一起创建。聚
集组件
的创建没什么特别之处,只是要注意它将查询IUnknown指针,并返回给m_pUnkAg
g.外部
组件将通过m_pUnkAgg操作聚集组件。另外注意到使用pUnkOuter作为CoCreateIn
stance
的参数,这将导致创建CComAggObject对象,内部包含一个CComContainedObject

的包含对象。向上一节中的CComCachedTearOff<>类似,CComAggObject也不是
从COuter派生的,所以真正的组件对象不是CComAggObject对象,而是它内部包

含的CComContainedObject对象。同样pUnkOuter得到的将是CComAggObject<>的

IUnknown指针,也同样调用它的QueryInterface会转而调用CComContainedObjec
t的
_InternalQueryInterface函数(呵呵,现在可都还是我猜的,看我猜的对不对吧


运行pOuter->QueryInterface(IID_IAgg, (void **)&pAgg1)
函数堆栈一:
9.ATL::AtlInternalQueryInterface(...)
8.ATL::CComObjectRootBase::InternalQueryInterface(...)
7.CAgg::_InternalQueryInterface(...)
6.ATL::CComAggObject::QueryInterface(...)
5.ATL::CComObjectRootBase::_Delegate(...)
4.ATL::AtlInternalQueryInterface(...)
3.ATL::CComObjectRootBase::InternalQueryInterface(...)
2.COuter::_InternalQueryInterface(...)
1.ATL::CComObject::QueryInterface(...)

解释:
1-5:这几步函数调用我们已经见了很多次了,因为在这个宏定义使用了_Delegat
e,所以
  将调用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_pUnkAg
g.
6:正如我们刚才所料,现在调用的是CComAggObject::QueryInterface()
  STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject)
  {
        //如果查询的是IUnknown,则....
        else
                hRes = m_contained._InternalQueryInterface(iid, ppvObj
ect);
        return hRes;
  }
  也正如我们所料,将交给它的包含对象去做.(这段代码在上一节好象也见过是吧
,呵呵)
7-9:同上一节一样,将交给CAgg::_InternalQueryInterface(...),剩下的工作将
由CAgg
  完成了。最后返回的指针实际上将是CComContainedObject组件的接口指针。



运行pAgg1->QueryInterface(IID_IAgg, (void **)&pAgg2)
函数堆栈二:
9.CAgg::_InternalQueryInterface(...)
8.ATL::CComAggObject::QueryInterface(...)
7.ATL::CComObjectRootBase::_Delegate(...)
6.ATL::AtlInternalQueryInterface(...)
5.ATL::CComObjectRootBase::InternalQueryInterface(...)
4.COuter::_InternalQueryInterface(...)
3.ATL::CComObject::QueryInterface(...)
2.ATL::CComObjectRootBase::OuterQueryInterface(...)
1.ATL::CComContainedObject::QueryInterface(...)

解释:
1-9:浏览整个堆栈,与我们上一节所见的堆栈二太相近了,这是因为都是使用了
包含对
  象。包含对象起了个代理的作用,他先把查询交给外部对象(COuter)去做(第1
,2步),
  当外部对象发现要查询的是聚集组件的接口时(IAgg),就会再把查询交还给它
保留的
  聚集组件的指针(m_pUnkAgg,第7步中,注意这不是真正的聚集组件),m_pUnkAgg
再把查
  询交给包含对象(第8步中),包含对象再把查询交给真正实现接口的类CAgg(第9
步).
  若外部对象发现要查询的是外部组件的接口时,那就很简单了,直接查询就行
了。这
  样就防止了外部组件与聚集组件查询操作的不一致性。
  唉,真个过程真麻烦,不过还好,与上一节的宏很类似。相关的源码可参看上
一节。


                -------------未完待续-------------

--
才疏学浅,胡言乱语;不对之处,敬请指正。



                路漫漫兮,其修远。
                吾将上下而求索。

※ 来源:.武汉白云黄鹤站 bbs.whnet.edu.cn.[FROM: 202.114.1.217]

--
...我是在黑夜里展翅飞翔的恐怖...

※ 来源:.月光软件站 http://www.moon-soft.com.[FROM: 61.129.25.213]

[关闭][返回]