为什么我为2个不同的实例获得相同的__vfptr?

时间:2011-11-10 16:12:24

标签: com idispatch

我对通过IDispatch / IUnknown指针看到的__vfptr感到困惑。 我正在创建进程内免费线程COM obj(IMyContainer)。在这个对象中,我需要保留指向实现相同IMyInterface的两个不同com对象实例的指针。所以我两次调用CreateAndSaveDispToMap()。

我的想法是将IDispatch指针保存在某些std :: map中。此时我怀疑每个实例的refCount都是1.它就是这样。但令人惊讶的是,我看到我通过pUnk为2个不同的调度指针获得相同的__vftbl。

为什么呢? AddRef()和Release()如何正常工作?

HRESULT CMyContainer::CreateAndSaveDispToMap(...)
{
...
IMyInterface* pMyInterface = NULL;
hr = ::CoCreateInstance(CLSID_MyInterface, NULL, CLSCTX_INPROC_SERVER, IID_IMyInterface, (void**)&pMyInterface);
pMyInterface->QueryInterface(IID_IDispatch, (void**)&pDisp);
pMyInterface->Release();    // Call Release since QI already called AddRef()
...

IUnknown* pUnk = NULL;
pDisp->QueryInterface(IID_IUnknown, (void**)&pUnk);
int refCount = pUnk->Release();
...
AddToMap(pDisp);
}

2 个答案:

答案 0 :(得分:0)

每个多态对象都有一个__vfptr,它是指向对象实际类的vtable的指针。每个不同的类生成一个vtable。这就是为什么对于同一类的任何两个对象,__vfptr s将具有相同的值。

区分不同的COM对象检索并比较它们的IUnknown接口指针。这叫做object identity

答案 1 :(得分:0)

谢谢,我发现IUnknown上函数的地址是相同的,必须如此。

但仍然不要低调AddRef / Release的行为。当我在ExposePointer()中进入调试模式时,我看到第二个连续调用不会将refCount带回3.它会将它恢复为2.

但如果我两次调用ForgetExposePointer(),它会将它带到3。

为什么通过Variant * Result返回调度指针或忘记返回这样的值会给我不同的结果?我在调用1和调用2之间的一些隐藏调用发生在()发生...

STDMETHODIMP CMyContainer::ExposePointer([in]int index, [out, retval] VARIANT* Result)
{
VariantInit(Result);
IDispatch* pDisp = m_map[index].second;
V_VT(Result) = VT_DISPATCH;
V_DISPATCH(Result) = pDisp;
refCount_x = pDisp->AddRef();    // Increment, because we expose
}

STDMETHODIMP CMyContainer::ForgetExposePointer([in]int index, [out, retval] VARIANT* Result)
{
VariantInit(Result);
IDispatch* pDisp = m_map[index].second;
refCount_y = pDisp->AddRef();
}


MyApp::Function1(...)
{
CreateAndSaveDispToMap(...);   // refCount is 1 now
VARIANT var1;
VARIANT var2;
pMyContainer->ExposePointer(index, &var1);  // Call 1
pMyContainer->ExposePointer(index, &var2);  // Call 2
}
MyApp::Function2(...)
{
CreateAndSaveDispToMap(...);   // refCount is 1 now
VARIANT var1;
VARIANT var2;
pMyContainer->ForgetExposePointer(index, &var1);
pMyContainer->ForgetExposePointer(index, &var2);
}