ATL对接口查询的支持
COM对象实现接口的方法是多种多样的,常用的有多重继承、聚合、tear-off等。为了最大限度地支持接口查询的多样性,ATL使用表驱动的方式来管理接口查询,以做到代码封闭和扩展灵活,表条目格式为:
struct
_ATL_INTMAP_ENTRY
{
const IID * piid;
DWORD_PTR dw;
_ATL_CREATORARGFUNC * pFunc;
};
{
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;
}
{
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},
{ & _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;
}
{
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},
{ & 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);
}
{
_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},
{ & 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};
{
_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来完成各种千奇百怪的接口实现方式,需要的只是想象力。