2011-11-10 3 views
1

나는 IDispatch/IUnknown 포인터를 통해 볼 수있는 __vfptr과 혼동을 느낍니다. in-proc 무료 스레드 된 COM obj (IMyContainer)를 만들고 있습니다. 이 객체 안에는 동일한 IMyInterface를 구현하는 com 객체의 두 개의 다른 인스턴스에 대한 포인터를 유지해야합니다. 그래서 CreateAndSaveDispToMap()을 두 번 호출합니다.왜 두 개의 다른 인스턴스에 대해 동일한 __vfptr을 얻고 있습니까?

제 아이디어는 일부 표준 :지도에서 IDispatch 포인터를 유지하는 것입니다. 이 순간 나는 각 인스턴스가 1의 refCount를 가질 것이라고 의심합니다. 그렇습니다. 그러나 놀랍게도 나는 2 개의 다른 디스패치 포인터에 대해 pUnk를 통해 동일한 __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); 
} 
+0

v 테이블은 주소 테이블 일뿐입니다. 모든 오브젝트 인스턴스에 대해 하나의 * v 테이블이 있으며 오브젝트 상태를 저장하지 않습니다. –

답변

0

각 다형성 객체는 객체의 실제 클래스의 vtable에 대한 포인터입니다 __vfptr있을 것이다. 개별 클래스마다 하나의 vtable이 생성됩니다. 이것이 동일한 클래스의 두 객체에 대해 동일한 값을 갖는 이유입니다.

다른 COM 개체를 구분하려면 해당 인터페이스 포인터 IUnknown을 검색하고 비교하십시오. 그건 object identity입니다.

0

감사합니다. IUnknown의 함수 주소가 같고 반드시 같아야합니다.

그러나 여전히 AddRef/Release의 동작을 강조하지 마십시오. ExposePointer()에서 디버그 모드로 들어가면 두 번째 결과 호출이 refCount를 3으로 가져 오지 않는다는 것을 알 수 있습니다. 다시 2로 가져옵니다.

그러나 ForgetExposePointer()를 두 번 호출하면 3.

Variant *를 통해 디스패치 포인터를 반환하는 이유 * 결과 또는 그 값을 반환하는 것을 잊어 버리면 결과가 달라 집니까? 통화 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); 
} 
관련 문제