3

我有一个进程外 COM 服务器,它有两个 ATL COM 对象。object1 公开了一个接口,该接口在内部创建 object2 并以下列方式返回一个指向它的接口指针:

HRESULT CObject1::CreateObject2(IObject2** pIobj2)
{
    CComObject<Object2>* pObj = NULL;

    HRESULT hr = CComObject<Object2>::CreateInstance(&pObj);

    hr = pObj->QueryInterface(IID_IObject2,(void**)pIobj2);

    //Some reason i need to store this pIobj2
    (*pIobj2)->AddRef();

    return hr;
}

Object1 暴露了另一个接口来移除 object2

HRESULT CObject1::RemoveObject2(IObject2* pIobj2)
{
    pIobj2->Release(); //This to compensate QI done in CreateObject2

    pIobj2->Release(); //This to compensate addref done to store in create
}

我的要求是客户端不应该IObject2IObject1::CreateObject2(). 要销毁 object2 它应该调用IObject1::RemoveObject2()。当我执行客户端时,在 RemoveObject2 之后,object2 不会被销毁,但是当我在 RemoveObject2 之后在客户端的 Iobject2 指针上调用 release 时,object2 会被销毁。

4

1 回答 1

2

进程外 COM 对象的生命周期管理比进程内复杂得多。例如,系统必须考虑到对方可能会死掉(例如,如果客户端进程在没有 Release 的情况下死掉,服务器应该清理为一个对象分配的资源)。为此,Microsoft 有一个 DCOM 垃圾收集。

确实有两个 COM 对象,在客户端(代理)和服务器(存根)上。代理维护自己的引用计数,并且您的代码混淆了这个引用计数,因为您在服务器上释放了对象 2 的引用计数 - 不会到达客户端的信息。

我强烈建议你改变你的架构。一方面,COM 契约是释放对象的方式是使用 Release 方法。这就是合同,你的设计改变了它,这就是你让 DCOM 感到困惑的原因。

我认为更好的设计是:

  1. 在 Object2 中保留对 Object1 的引用(例如,m_pobj1)
  2. 没有 Object1::RemoveObject2。如果您需要做一些工作,请改为使用私有(非 COM)CleanupObject2。
  3. 实现Object2::FinalRelease(Object2的清理方法),调用m_pobj1->Cleanup[Object2(this)
  4. 请记住,如果您需要在 obj1 中保留指向 obj2 的指针,请确保这些是引用。那就是 - 只是指针 - 没有添加引用计数。

客户端调用 Object1::CreateObject2 并获得对 obj2 的引用。完成后,它们会调用 obj2->Release(),并清除引用计数,并调用 obj1->CleanupObject2 方法。

于 2013-01-19T17:13:58.783 回答