I got confused with __vfptr which I see through IDispatch/IUnknown pointers. I'm creating in-proc free threaded COM obj (IMyContainer). Inside this object I need to keep pointers to 2 different instances of com objects which implements same IMyInterface. So I call CreateAndSaveDispToMap() twice.

My idea is to keep their IDispatch pointers in some std::map. At this moment I suspect that each instance will have refCount of 1. And it is so. But suprisingly I see that I am getting same __vftbl through pUnk for 2 different dispatch pointers.

Why? How it's possible that AddRef() and Release() works fine?

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);
}
有帮助吗?

解决方案

Each polymorphic object will have a __vfptr that is a pointer to the vtable of the actual class of the object. One vtable is generated per each distinct class. That's why for any two objects of the same class their __vfptrs will have identical values.

To distinguish between different COM objects retrieve and compare their IUnknown interface pointers. That's called object identity.

其他提示

Thanks, I figured out that function's addresses on IUnknown are the same and must be so.

But still don't undersatand the behaviour of AddRef/Release. When I step in debug mode in ExposePointer() I see that the second consequitive call will not bring refCount to 3. It will bring it back to 2.

But if I call ForgetExposePointer() twice instead it will bring it to 3.

Why returning dispatch pointer through Variant* Result or forgetting to return such value gives me different result? My undersanding that between Call 1 and Call 2 some hidden call to Release() occur...

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);
}
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top