【问题标题】:Why I am getting same __vfptr for 2 different instances?为什么我在 2 个不同的实例中得到相同的 __vfptr?
【发布时间】:2011-11-12 04:48:53
【问题描述】:

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

我的想法是将他们的 IDispatch 指针保存在一些 std::map 中。此时我怀疑每个实例的 refCount 都为 1。事实就是如此。但令人惊讶的是,我发现我通过 pUnk 获得了相同的 __vftbl 以获取 2 个不同的调度指针。

为什么? 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);
}

【问题讨论】:

  • v-table 只是一个地址表。所有对象实例都有一个 v-table,它不存储任何对象状态。

标签: com idispatch


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

    谢谢,我发现 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);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-09-14
      • 1970-01-01
      • 2018-05-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-14
      相关资源
      最近更新 更多