多继承情况下接口的取得。
1. 多Dispatch接口
class ATL_NO_VTABLE CUse :
public CComObjectRootEx <CComSingleThreadModel> ,
public CComCoClass <CUse, &CLSID_Parser> ,
public IDispatchImpl < IUse1, &IID_IParser, &LIBID_netfeesrvLib, /*wMajor =*/ 1, /*wMinor =*/ 0>
public IDispatchImpl < IUse2, &IID_IParser, &LIBID_netfeesrvLib, /*wMajor =*/ 1, /*wMinor =*/ 0>
{
public:
....
}
2. 接口分布结构:
pI -----> vptr1 ------> IUnkonwn
¦ IDispatch
dw IUse1
¦
----> vptr2 ------> IUnkonwn
IDispatch
IUse2
3. 接口映射表
BEGIN_COM_MAP(CUse)
COM_INTERFACE_ENTRY(IUse1)
COM_INTERFACE_ENTRY(IUse2)
COM_INTERFACE_ENTRY_IID(IDispatch, IUse2)
END_COM_MAP()
#define COM_INTERFACE_ENTRY(x)/
{&_ATL_IIDOF(x), /
offsetofclass(x, _ComMapClass), /
_ATL_SIMPLEMAPENTRY},
#define COM_INTERFACE_ENTRY_IID(iid, x)/
{&iid,/
offsetofclass(x, _ComMapClass),/
_ATL_SIMPLEMAPENTRY},
IUse1 ---- offsetofclass(IUse1, _ComMapClass) ---_ATL_SIMPLEMAPENTRY
IUse2 ---- offsetofclass(IUse2, _ComMapClass) ---_ATL_SIMPLEMAPENTRY
IDispatch -- offsetofclass(IUse2, _ComMapClass) ---_ATL_SIMPLEMAPENTRY <======= 选择IUse2计算接口偏移
4。
ATLINLINE ATLAPI AtlInternalQueryInterface(
void
*
pThis,
const
_ATL_INTMAP_ENTRY
*
pEntries, REFIID iid,
void
**
ppvObject)
{
ATLASSERT(pThis
!=
NULL);
//
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))
//
use first interface
{
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)
//
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);
if
(hRes
==
S_OK ¦ ¦ (
!
bBlind
&&
FAILED(hRes)))
return
hRes;
}
}
pEntries
++
;
}
return
E_NOINTERFACE;
}
通过
IUnknown* pUnk = (IUnknown*)((INT_PTR)pThis+pEntries-> dw);
来通过偏移量获得接口指针 --- *ppvObject = pUnk;
即:基类指针(pUnk)象子类指针(pIUser1, pIUser2)逆转换。
pIUser1 = pUnk;
pIUser2 = pUnk;
当要取得IDispatch时,根据程序作出的选择
IDispatch -- offsetofclass(IUse2, _ComMapClass) ---_ATL_SIMPLEMAPENTRY <======= 选择IUse2计算接口偏移
在这里就是计算出pIUse2的偏移量,取得接口指针 --- *ppvObject = pUnk;
即:基类指针(pUnk)象子类指针(pIDispatch)逆转换。
pIDispatch = pUnk;
由此可以看出,当实现象IDispatch这样的多继承时,需要类设计者决定IDispatch的走向:
IDispatch -- offsetofclass(IUse2, _ComMapClass) ---_ATL_SIMPLEMAPENTRY <======= 选择IUse2计算接口偏移
也就是说:
在COM_INTERFACE_ENTRY_IID(IDispatch, IUse2)中:
而IUse2决定取得接口指针的偏移量
IDispatch决定最终获得接口的类型--由*ppvObject = pUnk作隐式转换;