ATL学习笔记(3): QueryInterface功能的实现
来源:互联网 发布:淘宝假冒品牌申诉 编辑:程序博客网 时间:2024/06/12 23:12
在CComObjectRootEx类中,实现了线程安全的引用计数管理。而在CComObjectRootEx的父类CComObjectRootBase中,存在对QueryInterface的一个内部实现——InternalQueryface()。
1. CComObjectRootBase类
class CComObjectRootBase
{
public:
......
static HRESULT InternalQueryInterface(
void* pThis, const _ATL_INTMAP_ENTRY* pEntries, REFIID iid, void** ppvObj)
{ return hRes = AtlInternalQueryInterface(pThis, pEntries, iid, ppvObj); }
......
};
以上代码作了一些简化,去掉了调试用的条件编译选项。在代码中,InternalQueryInterface作为静态方法存在,并且仅仅将执行过程转给了AtlInternalQueryInterface()。其方法参数与标准的QueryInterface方法相比也有不同,其中也有一个新的结构类型_ATL_INTMAP_ENTRY,并且InternalQueryInterface和AtlInternalQueryInterface函数的参数一一对应。
2. _ATL_INTMAP_ENTRY结构和AtlInternalQueryInterface()函数
在atlbase.h中,_ATL_INTMAP_ENTRY结构类型有以下声明:
struct _ATL_INTMAP_ENTRY
{
const IID * piid;
DWORD_PTR dw;
_ATL_CREATORARGFUNC* pFunc;
};
其中piid表示接口的ID,其他的成员变量说明现在暂时无从知晓,只知_ATL_CREATORARGFUNC在atlbase.h中的声明是:
typedef HRESULT (WINAPI _ATL_CREATORARGFUNC) (
void* pv, REFIID riid, LPVOID* ppv, DWORD_PTR dw);
同样,这个函数类型在MSDN中也没有找到说明。
跳过这些暂时无法弄清的声明,看看AtlInternalQueryInterface()函数的实现:
ATLINLINE ATLAPI AtlInternalQueryInterface(void* pThis,
const _ATL_INTMAP_ENTRY* pEntries, REFIID iid, void** ppvObject)
{
if (InlineIsEqualUnknown(iid))
{
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))
{
if (pEntries->pFunc == _ATL_SIMPLEMAPENTRY)
{
IUnknown* pUnk = (IUnknown*)((INT_PTR)pThis+pEntries->dw);
pUnk->AddRef();
*ppvObject = pUnk;
return S_OK;
} else {
HRESULT hRes = pEntries->pFunc(pThis,
iid, ppvObject, pEntries->dw);
if (hRes == S_OK || (!bBlind && FAILED(hRes)))
return hRes;
}
}
pEntries++;
}
return E_NOINTERFACE;
}
参考MSDN,得知:
pThis - 指向包含有COM接口映射表的对象的指针;
pEntries - 一个_ATL_INTMAP_ENTRY结构类型的数组,该数组中包含有效的接口映射;
iid - 请求的接口的GUID;
ppvObj - 用以输出指向iid表示的接口的指针。
参照AtlInternalQueryInterface的实现,如果参数中的iid与IUnknown接口的iid相同(InlineIsEqualUnknown(iid))),将直接输出对象指针加上_ATL_INTMAP_ENTRY结构数组的第一个元素的dw成员的偏移。可见,在请求IUnknown时,函数返回的时pEntries数组中第一个元素表示的接口的IUnknown实现(因为每个COM接口都从IUnknown实现,在多重继承的前提下,函数只返回第一个接口的IUnknown)。
如果请求的接口不是IUnknown,则AtlInternalQueryInterface将继续搜索pEntries数组,直到存在一个元素,并且该元素的pFunc指针是NULL。可见,pEntries数组应该包含pThis所指向的COM对象所实现的所有接口,即所谓的COM对象接口映射表。并且,该数组中最后一个元素不表示任何接口且其pFunc成员应为NULL。
同时还可知,如果接口映射表元素的pFunc成员值为_ATL_SIMPLEMAPENTRY,dw成员则表示所对应的接口指针相对于pThis对象指针的偏移。否则pFunc指向一个自定义的接口指针计算函数。
3. 结论
根据上述分析,与AddRef和Release相似,ATL也没有直接实现IUnknown的QueryInterface方法,而同样是在CComObjectBase类中先作一个内部实现,该实现随着CComObjectRootEx被继承到每个COM对象中。
ATL对于QueryInterface的实现采用的是表驱动的方式(MFC也常用到表驱动方式,似乎是Microsoft钟情于表驱动这个方式,也可能这种方式的确在性能上有过人之处),因此每个ATL COM对象中必须首先存在一个包含其所有实现接口的接口映射表。
我想,下面应该去看看《接口映射表是怎样建成的》了。
- ATL学习笔记(3): QueryInterface功能的实现
- ATL学习笔记(3): QueryInterface功能的实现
- com学习笔记(2)基本的com接口-QueryInterface的实现
- com学习笔记(2)基本的com接口-QueryInterface的实现
- QueryInterface 的实现规则
- ATL是通过接口映射表来实现QueryInterface
- ATL学习笔记(1):ATL单线程与多线程套间对象引用计数的基础实现
- ATL学习笔记(2): ATL对象多线程访问临界锁的实现
- ATL学习笔记(1):ATL单线程与多线程套间对象引用计数的基础实现
- ATL学习笔记(2): ATL对象多线程访问临界锁的实现
- ATL窗口实现的学习
- IUnknown中的QueryInterface的实现剖析(1)
- IUnknown中的QueryInterface的实现剖析(2)
- ATL学习笔记01
- ATL学习笔记02
- ATL学习笔记03
- ATL学习笔记02
- ATL学习笔记03
- DSPLINK DEMO解析之SCALE【转】
- Postel ActiveX Control支持Postel的ActiveX控件
- PL/SQL 查询中文乱码问题
- 字符流 vs 字节流
- Android页面切换时的动画效果(overridePendingTransition)
- ATL学习笔记(3): QueryInterface功能的实现
- pk12 证书生成 用于RSA非对称加密
- 欢迎来到Swift的世界(Welcome to Swift)
- 收藏的JAVA面试题大全
- NORDIC(一)Nordic_Keil的内存配置
- UML 状态图
- ATL学习笔记(4): COM接口映射表
- 北京大额股票配资 北京股票金融配资
- 好好经营你的30-47岁!