Почему я получаю один и тот же __vfptr для 2 разных экземпляров? - PullRequest
1 голос
/ 10 ноября 2011

Я запутался с __vfptr, который я вижу через указатели IDispatch / IUnknown.Я создаю внутрипроцессный свободный поток COM-объект (IMyContainer).Внутри этого объекта мне нужно сохранить указатели на 2 разных экземпляра com-объектов, которые реализуют один и тот же IMyInterface.Поэтому я дважды вызываю CreateAndSaveDispToMap ().

Моя идея - сохранить указатели IDispatch в некотором std :: map.На данный момент я подозреваю, что каждый экземпляр будет иметь refCount 1. И это так.Но на удивление я вижу, что я получаю один и тот же __vftbl через pUnk для двух разных указателей отправки.

Почему?Как это возможно, что 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 голосов
/ 11 ноября 2011

Спасибо, я понял, что адреса функций в IUnknown одинаковы и должны быть такими.

Но все же не недооценивайте и поведение AddRef / Release. Когда я вхожу в режим отладки в ExposePointer (), я вижу, что второй последовательный вызов не принесет refCount к 3. Это вернет его к 2.

Но если я дважды вызову ForgetExposePointer (), вместо этого он достигнет 3.

Почему возвращение указателя отправки через Variant * Result или забвение возврата такого значения дает мне другой результат? Мое понимание того, что между Call 1 и Call 2 происходит скрытый вызов Release () ...

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);
}
0 голосов
/ 11 ноября 2011

Каждый полиморфный объект будет иметь __vfptr, который является указателем на виртуальную таблицу фактического класса объекта.Один Vtable генерируется для каждого отдельного класса.Вот почему для любых двух объектов одного и того же класса их __vfptr s будут иметь одинаковые значения.

Чтобы различать различные COM-объекты, извлекайте и сравнивайте их IUnknown указатели интерфейса.Это называется идентификатор объекта .

...