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功能,详见原书
本文详细解析了COM接口映射宏的使用方法及其在解决多重继承二义性方面的作用,包括COM_INTERFACE_ENTRY_IID等宏如何帮助开发者清晰地定义接口映射。
3740

被折叠的 条评论
为什么被折叠?



