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 阅读(668)
评论(0) 编辑 收藏 引用 所属分类:
心得