1. ATL的QueryInterface调用追踪
a. 组件的QueryInterface函数定义
[cpp] view plain copy
template <class Base>
class CComObject : public Base
{
STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject) throw() //QueryInterface函数
{return _InternalQueryInterface(iid, ppvObject);}
}
b. _InternalQueryInterface函数调用InternalQueryInterface函数,定义在BEGIN_COM_MAP宏内部
#define BEGIN_COM_MAP(x) public: / typedef x _ComMapClass; / static HRESULT WINAPI _Cache(void* pv, REFIID iid, void** ppvObject, DWORD_PTR dw) throw()/ {/ _ComMapClass* p = (_ComMapClass*)pv;/ p->Lock();/ HRESULT hRes = E_FAIL; / __try / { / hRes = ATL::CComObjectRootBase::_Cache(pv, iid, ppvObject, dw);/ } / __finally / { / p->Unlock();/ } / return hRes;/ }/ IUnknown* _GetRawUnknown() throw() / { ATLASSERT(_GetEntries()[0].pFunc == _ATL_SIMPLEMAPENTRY); return (IUnknown*)((INT_PTR)this+_GetEntries()->dw); } / _ATL_DECLARE_GET_UNKNOWN(x)/ HRESULT _InternalQueryInterface(REFIID iid, void** ppvObject) throw() / { return InternalQueryInterface(this, _GetEntries(), iid, ppvObject); } / const static ATL::_ATL_INTMAP_ENTRY* WINAPI _GetEntries() throw() { / static const ATL::_ATL_INTMAP_ENTRY _entries[] = { DEBUG_QI_ENTRY(x)
c. InternalQueryInterface函数定义在CComObjectRootBase类中(这里显示的代码已经删除了调试扩展的内容)。
[cpp] view plain copy
static HRESULT WINAPI InternalQueryInterface(void* pThis,
const _ATL_INTMAP_ENTRY* pEntries, REFIID iid, void** ppvObject)
{
HRESULT hRes = AtlInternalQueryInterface(pThis, pEntries, iid, ppvObject);
return hRes;
}
InternalQueryInterface委派全局函数AtlInternalQueryInterface来提供接口查询的实现。在查询接口之前,先检查查询的接口IID,如果请求的是IUnknown,从表中取出第一个表项立即返回,不需要偏历表的剩余部分。 关于表的遍历,对于表中的每个表项,根据指向表项接口标识符的piid成员是否为NULL。 1. 如果不为NULL,表项IID与请求IID进行比较,如果匹配,pFunc引用的函数被调用,结果返回客户。如果不匹配,进入下一个表现搜索。 2. 如果piid为NULL,则不管请求的IID是什么,都会调用pFunc。如果接口是S_OK,则返回结果给客户。否则继续搜索下一个表项。所有的COM_INTERFACE_ENTRY_XXX_BLIND宏都使用了这种行为。比如COM_INTERFACE_ENTRY_AGGREGATE_BLIND。
[cpp] view plain copy
/////////////////////////////////////////////////////////////////////////////
// QI support
ATLINLINE ATLAPI AtlInternalQueryInterface(void* pThis,
const _ATL_INTMAP_ENTRY* pEntries, REFIID iid, void** ppvObject)
{
ATLASSERT(pThis != NULL);
ATLASSERT(pEntries!= NULL);
if(pThis == NULL || pEntries == NULL)
return E_INVALIDARG ;
// First entry in the com map should be a simple map entry
ATLASSERT(pEntries->pFunc == _ATL_SIMPLEMAPENTRY);
if (ppvObject == NULL)
return E_POINTER;
*ppvObject = NULL;
if (InlineIsEqualUnknown(iid)) // 请求的是IUnknown接口
{
IUnknown* pUnk = (IUnknown*)((INT_PTR)pThis+pEntries->dw);
pUnk->AddRef();
*ppvObject = pUnk;
return S_OK;
}
while (pEntries->pFunc != NULL)
{
BOOL bBlind = (pEntries->piid == NULL); //表示的是盲目聚合,即聚合所有的接口
if (bBlind || InlineIsEqualGUID(*(pEntries->piid), iid))//piid是否与iid相等
{
if (pEntries->pFunc == _ATL_SIMPLEMAPENTRY) //offset
{
ATLASSERT(!bBlind);
IUnknown* pUnk = (IUnknown*)((INT_PTR)pThis+pEntries->dw);
pUnk->AddRef();
*ppvObject = pUnk;
return S_OK;
}
else //actual function call
{
HRESULT hRes = pEntries->pFunc(pThis,
iid, ppvObject, pEntries->dw);
//常用的pFunc函数在CComObjectRootBase函数中有定义,
//包括_Creator、_Delegate、_ChainAttr、_Cache、_Break、_NoInterface
if (hRes == S_OK || (!bBlind && FAILED(hRes)))
return hRes;
}
}
pEntries++;
}
return E_NOINTERFACE;
}
2.接口映射表的源码分析 通过上面的函数调用追踪,我们可以发现函数最终是遍历_ATL_INTMAP_ENTRY数组结构。关于_ATL_INTMAP_ENTRY数组的定义在BEGIN_COM_MAP宏内部。是一个静态数据变量。
[cpp] view plain copy
HRESULT _InternalQueryInterface(REFIID iid, void** ppvObject) throw() /
{ return InternalQueryInterface(this, _GetEntries(), iid, ppvObject); } /
const static ATL::_ATL_INTMAP_ENTRY* WINAPI _GetEntries() throw() { /
static const ATL::_ATL_INTMAP_ENTRY _entries[] = { DEBUG_QI_ENTRY(x)
......
......
__if_exists(_GetAttrEntries) {{NULL, (DWORD_PTR)_GetAttrEntries, _ChainAttr }, }/
{NULL, 0, 0}}; /
return &_entries[1];}
下面我们来看看_ATL_INTMAP_ENTRY结构的定义
[cpp] view plain copy
struct _ATL_INTMAP_ENTRY
{
const IID* piid; // 接口的IID
DWORD_PTR dw;
_ATL_CREATORARGFUNC* pFunc; //NULL:end, 1:offset, n:ptr
};
_ATL_CREATORARGFUNC函数类型的定义
[cpp] view plain copy
typedef HRESULT (WINAPI _ATL_CREATORARGFUNC)(void* pv, //对象的this指针
REFIID riid, //请求的接口IID
LPVOID* ppv, //存储返回的结构指针
DWORD_PTR dw);//来源于接口映射表项的dw
3.常用的 pFunc 函数的定义
常用的pFunc函数在CComObjectRootBase函数中有定义,其中包括_Creator、_Delegate、_ChainAttr、_Cache、_Break、_NoInterface。
[cpp] view plain copy
//1.函数功能说明:_Break函数主要用于调试,追查问题的所在
//2.相关的宏: COM_INTERFACE_ENTRY_BREAK(x)
// {&_ATL_IIDOF(x), NULL, _Break},
static HRESULT WINAPI _Break(void* /* pv */, REFIID iid, void** /* ppvObject */, DWORD_PTR /* dw */)
{
(iid);
_ATLDUMPIID(iid, _T("Break due to QI for interface "), S_OK);
DebugBreak();
return S_FALSE;
}
//1.函数功能说明:_NoInterface函数主要用于屏蔽指定的接口,例如当盲目聚合某些组件时,可能需要屏蔽一些接口
//2.相关的宏: COM_INTERFACE_ENTRY_NOINTERFACE(x)
// {&_ATL_IIDOF(x), NULL, _NoInterface},
static HRESULT WINAPI _NoInterface(void* /* pv */, REFIID /* iid */, void** /* ppvObject */, DWORD_PTR /* dw */)
{
return E_NOINTERFACE;
}
//1.函数功能说明:_Creator主要用于Tear-off技术中,用于创建子对象组件
//2.相关的宏: COM_INTERFACE_ENTRY_TEAR_OFF(iid, x)
// {&iid,(DWORD_PTR)&ATL::_CComCreatorData</
// ATL::CComInternalCreator< ATL::CComTearOffObject< x > >>::data, _Creator},
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);
}
//1.函数功能说明:_Cache主要用于Tear-off和聚合技术中,除了有创建内部组件对象功能外,还要将内部对象组件的指针保存
//2.相关的宏: a. COM_INTERFACE_ENTRY_CACHED_TEAR_OFF(iid, x, punk) 缓存tear-off
// {&iid,(DWORD_PTR)&ATL::_CComCacheData<ATL::CComCreator< ATL::CComCachedTearOffObject< x > >,/
// (DWORD_PTR)offsetof(_ComMapClass, punk)>::data,_Cache}, //
// b. COM_INTERFACE_ENTRY_AUTOAGGREGATE(iid, punk, clsid)
// {&iid,(DWORD_PTR)&ATL::_CComCacheData<ATL::CComAggregateCreator<_ComMapClass, &clsid>,/
// (DWORD_PTR)offsetof(_ComMapClass, punk)>::data,_Cache},
// c.COM_INTERFACE_ENTRY_AUTOAGGREGATE_BLIND(punk, clsid)
// {NULL,(DWORD_PTR)&ATL::_CComCacheData<ATL::CComAggregateCreator<_ComMapClass, &clsid>,/
// (DWORD_PTR)offsetof(_ComMapClass, punk)>::data,_Cache},
static HRESULT WINAPI _Cache(void* pv, REFIID iid, void** ppvObject, DWORD_PTR dw)
{
HRESULT hRes = E_NOINTERFACE;
_ATL_CACHEDATA* pcd = (_ATL_CACHEDATA*)dw;
IUnknown** pp = (IUnknown**)((DWORD_PTR)pv + pcd->dwOffsetVar);
if (*pp == NULL)
hRes = pcd->pFunc(pv, __uuidof(IUnknown), (void**)pp);
if (*pp != NULL)
hRes = (*pp)->QueryInterface(iid, ppvObject);
return hRes;
}
//1.函数功能说明:_Delegate主要用于聚合技术中,
// 和_Cache主要区别是需要客户手动创建内部组件对象,一般在FinalConstruct中创建内部对象
//2.相关的宏: a. COM_INTERFACE_ENTRY_AGGREGATE(iid, punk)
// {&iid,(DWORD_PTR)offsetof(_ComMapClass, punk),_Delegate}
// b. COM_INTERFACE_ENTRY_AGGREGATE_BLIND(punk)
// {NULL,(DWORD_PTR)offsetof(_ComMapClass, punk),_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;
}
//1.函数功能说明:_Chain主要用于继承基类的映射链表
// 从一个自己提供了接口映射表的基类继承时,在派生类的接口映射表中避免重复的表项,方便维护
//2.相关的宏: COM_INTERFACE_ENTRY_CHAIN(classname)/
// {NULL,(DWORD_PTR)&ATL::_CComChainData<classname, _ComMapClass>::data,_Chain},
static HRESULT WINAPI _Chain(void* pv, REFIID iid, void** ppvObject, DWORD_PTR dw)
{
_ATL_CHAINDATA* pcd = (_ATL_CHAINDATA*)dw;
void* p = (void*)((DWORD_PTR)pv + pcd->dwOffset);
return InternalQueryInterface(p, pcd->pFunc(), iid, ppvObject);
}
static HRESULT WINAPI _ChainAttr(void* pv, REFIID iid, void** ppvObject, DWORD_PTR dw)
{
const _ATL_INTMAP_ENTRY* (WINAPI *pFunc)() = (const _ATL_INTMAP_ENTRY* (WINAPI *)())dw;
const _ATL_INTMAP_ENTRY *pEntries = pFunc();
if (pEntries == NULL)
return S_OK;
return InternalQueryInterface(pv, pEntries, iid, ppvObject);
}
4.ATL接口的查询的扩展 #define COM_INTERFACE_ENTRY_FUNC(iid, dw, func)/ {&iid, dw, func}, #define COM_INTERFACE_ENTRY_FUNC_BLIND(dw, func)/ {NULL, dw,func}, 这两个宏其实是ATL的QueryInterface实现的通用后门,用户可以自定义func,在func函数中暴露COM接口,但需要遵守COM实体身份规则。