随笔-6  评论-0  文章-16  trackbacks-0

COM对象实现接口的方法是多种多样的,常用的有多重继承、聚合、tear-off等。为了最大限度地支持接口查询的多样性,ATL使用表驱动的方式来管理接口查询,以做到代码封闭和扩展灵活,表条目格式为:

struct  _ATL_INTMAP_ENTRY
{
    
const  IID *  piid; 
    DWORD_PTR dw;
    _ATL_CREATORARGFUNC
*  pFunc; 
};


piid是接口ID,dw为自定义参数,pFunc是自定义函数的地址。在QueryInterface时,ATL调用pFunc,并将dw传给pFunc,pFunc可以根据自己的需要解析dw,获得查询必需的信息。ATL预提供了一些函数来处理上述常用的查询请求,如_Creator、_Delegate等,它们被放置于CComObjectRootBase中。

(1)多重继承
           ATL并没有提供支持多重继承的函数,而是将pFunc设置为_ATL_SIMPLEMAPENTRY宏,将dw设为父类子对象在子类对象中的偏移量,当搜索表时发现pFunc为_ATL_SIMPLEMAPENTRY时,便直接使用偏移量相加获得结果。

            if  (pEntries -> pFunc  ==  _ATL_SIMPLEMAPENTRY) 
            {
                IUnknown *  pUnk  =  (IUnknown * )((INT_PTR)pThis + pEntries -> dw);
                pUnk
-> AddRef();
                
* ppvObject  =  pUnk;
                
return  S_OK;
            }

         接口映射表项宏为:

         #define  COM_INTERFACE_ENTRY(x)\
             {
& _ATL_IIDOF(x), \
             offsetofclass(x, _ComMapClass), \
             _ATL_SIMPLEMAPENTRY},


(2)聚合
           ATL使用_Delegate函数来支持聚合,此时dw存储的是内部对象指针成员变量在外部对象中的偏移量,_Delegate利用此偏移量获得内部对象指针,然后将查询调用委托给它。

    static  HRESULT WINAPI _Delegate( void *  pv, REFIID iid,  void **  ppvObject, DWORD_PTR dw)
    {
        HRESULT hRes 
=  E_NOINTERFACE;
        IUnknown
*  p  =   * (IUnknown ** )((DWORD_PTR)pv  +  dw);
        
if  (p  !=  NULL)
            hRes 
=  p -> QueryInterface(iid, ppvObject);
        
return  hRes;
    }
   
         接口映射表项宏为:

      #define COM_INTERFACE_ENTRY_AGGREGATE(iid, punk)\
          {
&iid,\
          (DWORD_PTR)offsetof(_ComMapClass, punk),\
          _Delegate},
   
(3)tear-off
           ATL使用_Creator函数来支持tear-off,此时dw中存储的是一个静态_ATL_CREATORDATA结构的地址,_Creator利用其中的指向创建函数的指针创建一个tear-off对象。
                  
         static HRESULT WINAPI _Creator(void* pv, REFIID iid, void** ppvObject, DWORD_PTR dw)
         {
              _ATL_CREATORDATA
* pcd = (_ATL_CREATORDATA*)dw;
              
return pcd->pFunc(pv, iid, ppvObject);
         }

         接口映射表项宏为:
            
      #define COM_INTERFACE_ENTRY_TEAR_OFF(iid, x)\
          {
&iid,\
          (DWORD_PTR)
&ATL::_CComCreatorData<\
              ATL::CComInternalCreator
< ATL::CComTearOffObject< x > >\
              
>::data,\
          _Creator},

      _ComCreatorData的相关定义如下:
      
struct _ATL_CREATORDATA
{
    _ATL_CREATORFUNC
* pFunc;
};

template 
<class Creator>
class _CComCreatorData
{
public:
    
static _ATL_CREATORDATA data;
};

template 
<class Creator>
_ATL_CREATORDATA _CComCreatorData
<Creator>::data = {Creator::CreateInstance};


      我们还可以定义自己的接口查询辅助函数和辅助数据,通过dw和pFunc来完成各种千奇百怪的接口实现方式,需要的只是想象力。
posted on 2007-04-30 11:37 michael 阅读(675) 评论(0)  编辑 收藏 引用 所属分类: 心得

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   博问   Chat2DB   管理