ATL Internals 2ed复习.chapter 6.各种interface map宏

COM_INTERFACE_ENTRY and COM_INTERFACE_ENTRY_IID

#define COM_INTERFACE_ENTRY_IID(iid, x) \                      
  { &iid, offsetofclass(x, _ComMapClass), _ATL_SIMPLEMAPENTRY},


COM_INTERFACE_ENTRY_IID的作用是消除多重继承的二义性

例如:

interface IGlobe : ISphere {};
interface IPlanet : ISphere {};


编译器无法得知ISphere应该指什么:

class CDesktopGlobe :
  public CComObjectRootEx<CDesktopGlobe>,
  public IGlobe,
  public IPlanet {
public:
  ...
BEGIN_COM_MAP(CDesktopGlobe)
  COM_INTERFACE_ENTRY(ISphere) // ambiguous
  COM_INTERFACE_ENTRY(IGlobe)
  COM_INTERFACE_ENTRY(IPlanet)
END_COM_MAP()
  // ISphere methods
  ...
  // IGlobe methods
  ...
  // IPlanet methods
  ...
};


改进的做法是,但是这带来了顺序问题,如果用户先调用IGlobe然后获取ISphere,用户接着访问IPlanet获取的ISphere得到的行为是不同的:

class CDesktopGlobe :
  public CComObjectRootEx<CDesktopGlobe>,
  public IGlobe,
  public IPlanet {
public:
...
BEGIN_COM_MAP(CDesktopGlobe)
  COM_INTERFACE_ENTRY_IID(IID_ISphere, IGlobe) // unambiguous
  COM_INTERFACE_ENTRY(IGlobe)
  COM_INTERFACE_ENTRY(IPlanet)
END_COM_MAP()
...
};


COM_INTERFACE_ENTRY2 and COM_INTERFACE_ENTRY2_IID

#define COM_INTERFACE_ENTRY2(x, x2)\                
  { &_ATL_IIDOF(x),\                                
    reinterpret_cast<DWORD_PTR>( \                  
      static_cast<x*>( \                            
        static_cast<x2*>( \                         
          reinterpret_cast<_ComMapClass*>(8))))-8, \
    _ATL_SIMPLEMAPENTRY},                           
                                                    
#define COM_INTERFACE_ENTRY2_IID(iid, x, x2)\       
  { &iid,\                                          
    reinterpret_cast<DWORD_PTR>( \                  
      static_cast<x*>( \                            
        static_cast<x2*>( \                         
          reinterpret_cast<_ComMapClass*>(8))))-8, \
      _ATL_SIMPLEMAPENTRY},                         


COM_INTERFACE_ENTRY2所做的工作和COM_INTERFACE_ENTRY_IID基本类似,例如:

class CDesktopGlobe :
  public CComObjectRootEx<CDesktopGlobe>,
  public IGlobe,
  public IPlanet {
public:
...
BEGIN_COM_MAP(CDesktopGlobe)
  COM_INTERFACE_ENTRY2(ISphere, IGlobe) // Use the IGlobal branch
  COM_INTERFACE_ENTRY(IGlobe)
  COM_INTERFACE_ENTRY(IPlanet)
END_COM_MAP()
...
};


COM_INTERFACE_ENTRY2_IID则可以确定IID和interface,例如:

class CDesktopGlobe :
  public CComObjectRootEx<CDesktopGlobe>,
  public IGlobe,
  public IPlanet {
public:
...
BEGIN_COM_MAP(CDesktopGlobe)
  COM_INTERFACE_ENTRY2_IID(&IID_ISphere, ISphere, IGlobe)
  COM_INTERFACE_ENTRY(IGlobe)
  COM_INTERFACE_ENTRY(IPlanet)
END_COM_MAP()
...
};


COM_INTERFACE_ENTRY_IMPL and COM_INTERFACE_ENTRY_IMPL_IID

#define COM_INTERFACE_ENTRY_IMPL(x) \                          
  COM_INTERFACE_ENTRY_IID(_ATL_IIDOF(x), x##Impl<_ComMapClass>)
                                                                      
#define COM_INTERFACE_ENTRY_IMPL_IID(iid, x) \                 
  COM_INTERFACE_ENTRY_IID(iid, x##Impl<_ComMapClass>)          

该宏基本被淘汰


COM_INTERFACE_ENTRY_TEAR_OFF

该类可以用于不常用的功能,以期减少内存开销

#define COM_INTERFACE_ENTRY_TEAR_OFF(iid, x) \                   
  { &iid, \                                                      
    (DWORD_PTR)&ATL::_CComCreatorData< \                         
        ATL::CComInternalCreator< ATL::CComTearOffObject< x > > \
          >::data, \                                             
  _Creator },                                                    


例如:

class CBeachBall :
  public CComObjectRootEx<CBeachBall>,
  public ISphere,
  public IRollableObject,
  public IPlaything,
  //public ILethalObject, // Implemented by the tear-off
  public ITakeUpSpace,
  public IWishIWereMoreUseful,
  public ITryToBeHelpful,
  public IAmDepressed {
public:
BEGIN_COM_MAP(CBeachBall)
  COM_INTERFACE_ENTRY(ISphere)
  COM_INTERFACE_ENTRY(IRollableObject)
  COM_INTERFACE_ENTRY(IPlaything)
  COM_INTERFACE_ENTRY_TEAR_OFF(IID_ILethalObject,
    CBeachBallLethalness)
  COM_INTERFACE_ENTRY(ITakeUpSpace)
  COM_INTERFACE_ENTRY(IWishIWereMoreUseful)
  COM_INTERFACE_ENTRY(ITryToBeHelpful)
  COM_INTERFACE_ENTRY(IAmDepressed)
END_COM_MAP()
...
private:
  GAS_TYPE m_gasFill;
  void     HoldNearOpenFlame();
  // Tear-offs are generally friends
  friend class CBeachBallLethalness;
};


应该注意:

tear-off目的是不常用的接口

tear-off不能用于跨套间

tear-off实现类不能含自己的state,如果想实现per-interface tearoff state,使用cached tear-off

COM_INTERFACE_ENTRY_CACHED_TEAR_OFF

#define COM_INTERFACE_ENTRY_CACHED_TEAR_OFF(iid, x, punk) \
  { &iid, \                                                
    (DWORD_PTR)&ATL::_CComCacheData< \                     
    ATL::CComCreator< ATL::CComCachedTearOffObject< x > >, \
    (DWORD_PTR)offsetof(_ComMapClass, punk) >::data, \      
    _Cache },                                               


例子:

class CBeachBall :
  public CComObjectRootEx<CBeachBall>,
  public ISphere,
  public IRollableObject,
  public IPlaything {
public:
BEGIN_COM_MAP(CBeachBall)
  COM_INTERFACE_ENTRY(ISphere)
  COM_INTERFACE_ENTRY(IRollableObject)
  COM_INTERFACE_ENTRY(IPlaything)
  COM_INTERFACE_ENTRY_TEAR_OFF(IID_ILethalObject,
    CBeachBallLethalness)
  COM_INTERFACE_ENTRY_CACHED_TEAR_OFF(IID_ITakeUpSpace,
    CBeachBallAttitude, m_spunkAttitude.p)
  COM_INTERFACE_ENTRY_CACHED_TEAR_OFF(IID_IWishIWereMoreUseful,
    CBeachBallAttitude, m_spunkAttitude.p)
  COM_INTERFACE_ENTRY_CACHED_TEAR_OFF(IID_ITryToBeHelpful,
    CBeachBallAttitude, m_spunkAttitude.p)
  COM_INTERFACE_ENTRY_CACHED_TEAR_OFF(IID_IAmDepressed,
    CBeachBallAttitude, m_spunkAttitude.p)
END_COM_MAP()
DECLARE_GET_CONTROLLING_UNKNOWN() // See the Aggregation section
...
public:
  CComPtr<IUnknown> m_spunkAttitude;
};

COM_INTERFACE_ENTRY_AGGREGATE and COM_INTERFACE_ENTRY_AGGREGATE_BLIND

#define COM_INTERFACE_ENTRY_AGGREGATE(iid, punk) \             
  { &iid, (DWORD_PTR)offsetof(_ComMapClass, punk), _Delegate },
                                                                   
#define COM_INTERFACE_ENTRY_AGGREGATE_BLIND(punk) \            
  { NULL, (DWORD_PTR)offsetof(_ComMapClass, punk), _Delegate}, 


例子:

class CBeachBall :
  public CComObjectRootEx<CBeachBall>,
  public ISphere,
  public IRollableObject,
  public IPlaything {
public:
BEGIN_COM_MAP(CBeachBall)
  COM_INTERFACE_ENTRY(ISphere)
  COM_INTERFACE_ENTRY(IRollableObject)
  COM_INTERFACE_ENTRY(IPlaything)
  COM_INTERFACE_ENTRY_AGGREGATE(IID_ILethalObject,
    m_spunkLethalness)
  COM_INTERFACE_ENTRY_AGGREGATE_BLIND(m_spunkAttitude)
END_COM_MAP()

DECLARE_GET_CONTROLLING_UNKNOWN()
DECLARE_PROTECT_FINAL_CONSTRUCT()

  HRESULT FinalConstruct() {
    HESULT hr;
    hr = CoCreateInstance(CLSID_Lethalness,
                          GetControllingUnknown(),
                          CLSCTX_INPROC_SERVER,
                          IID_IUnknown,
                          (void**)&m_spunkLethalness);
    if( SUCCEEDED(hr) ) {
    hr = CoCreateInstance(CLSID_Attitude,
                           GetControllingUnknown(),
                           CLSCTX_INPROC_SERVER,
                           IID_IUnknown,
                           (void**)&m_spunkAttitude);
   }

   return hr;
 }

 void FinalRelease() {
   m_spunkLethalness.Release();
   m_spunkAttitude.Release();
 }
...
public:
  CComPtr<IUnknown> m_spunkLethalness;
  CComPtr<IUnknown> m_spunkAttitude;
};

注意上面要在FinalXXX中创建和消灭对象,并且需要定义DECLARE_GET_CONTROLLING_UNKNOWN()宏

#define DECLARE_GET_CONTROLLING_UNKNOWN() public: \
  virtual IUnknown* GetControllingUnknown() { \    
    return GetUnknown(); }                         



COM_INTERFACE_ENTRY_AUTOAGGREGATE and COM_INTERFACE_ENTRY_AUTOAGGREGATE_BLIND

#define COM_INTERFACE_ENTRY_AUTOAGGREGATE(iid, punk, clsid) \ 
  { &iid, \                                                   
    (DWORD_PTR)&ATL::_CComCacheData< \                        
     ATL::CComAggregateCreator<_ComMapClass, &clsid>, \       
    (DWORD_PTR)offsetof(_ComMapClass, punk)>::data, \         
    _Cache },                                                 
                                                              
#define COM_INTERFACE_ENTRY_AUTOAGGREGATE_BLIND(punk, clsid) \
  { NULL, \                                                   
    (DWORD_PTR)&ATL::_CComCacheData< \                       
     ATL::CComAggregateCreator<_ComMapClass, &clsid>, \      
    (DWORD_PTR)offsetof(_ComMapClass, punk)>::data, \        
    _Cache },                                                

用了Auto,不再需要在FinalXXX中创建和销毁,但仍然需要定义DECLARE_GET_CONTROLLING_UNKNOWN()宏,例子:

class CBeachBall :
  public CComObjectRootEx<CBeachBall>,
  public ISphere,
  public IRollableObject,
  public IPlaything {
public:
BEGIN_COM_MAP(CBeachBall)
  COM_INTERFACE_ENTRY(ISphere)
  COM_INTERFACE_ENTRY(IRollableObject)
  COM_INTERFACE_ENTRY(IPlaything)
  COM_INTERFACE_ENTRY_AUTOAGGREGATE(IID_ILethalObject,
    m_spunkLethalness, CLSID_Lethalness)
  COM_INTERFACE_ENTRY_AUTOAGGREGATE_BLIND(m_spunkAttitude,
    CLSID_Attitude)
END_COM_MAP()

DECLARE_GET_CONTROLLING_UNKNOWN()

  void FinalRelease() {
    m_spunkLethalness.Release();
    m_spunkAttitude.Release();
  }
...
public:
  CComPtr<IUnknown> m_spunkLethalness;
  CComPtr<IUnknown> m_spunkAttitude;
};



COM_INTERFACE_ENTRY_CHAIN

#define COM_INTERFACE_ENTRY_CHAIN(classname) \        
  { NULL, (DWORD_PTR)&ATL::_CComChainData<classname, \
    _ComMapClass>::data, _Chain },                    


使用该宏不再需要一个一个定义IID和接口,例子:

class CBigBadBeachBall :
  public CBeachBall,
  public IBigObject,
  public IBadObject {
public:
BEGIN_COM_MAP(CBigBadBeachBall)
  COM_INTERFACE_ENTRY(IBigObject)
  COM_INTERFACE_ENTRY_CHAIN(CBeachBall)
  COM_INTERFACE_ENTRY(IBadObject)
END_COM_MAP()
...
};

trick:由于interface map首项的特殊性,不可以一上来就chain,如果找不到合适的首项,可以考虑IUnknown,例子:

class CBetterBeachBall :
  public CBeachBall {
public:
BEGIN_COM_MAP(CBetterBeachBall)
  COM_INTERFACE_ENTRY(IUnknown)
  COM_INTERFACE_ENTRY_CHAIN(CBeachBall)
END_COM_MAP()
...
};


COM_INTERFACE_ENTRY_NOINTERFACE

#define COM_INTERFACE_ENTRY_NOINTERFACE(x) \
  { &_ATL_IIDOF(x), NULL, _NoInterface },   

有时类查询需要做减法,如果你不想用户看到某个接口,或者在做了blind或chaining后去掉某个功能

例子:

class CBigNiceBeachBall :
  public CBeachBall,
  public IBigObject {
public:
BEGIN_COM_MAP(CBigNiceBeachBall)
  COM_INTERFACE_ENTRY(IBigObject)
  COM_INTERFACE_ENTRY_NOINTERFACE(ILethalObject)
  COM_INTERFACE_ENTRY_CHAIN(CBeachBall)
END_COM_MAP()
...
};


COM_INTERFACE_ENTRY_BREAK

#define COM_INTERFACE_ENTRY_BREAK(x) \
  { &_ATL_IIDOF(x), NULL, _Break },   


如果发现某个接口异常,可以用这个宏,当访问该接口时会自动break

COM_INTERFACE_ENTRY_FUNC and COM_INTERFACE_ENTRY_FUNC_BLIND

用户可以通过这个宏自定义查表函数,扩展interface map功能,详见原书

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值