背景

我正在使用的应用程序有几个 COM DLL。

其中一个 COM DLL 具有一个全局单例对象,该对象存储指向其他 DLL 中的 COM 接口的指针。因为它是一个全局单例对象,所以我使用了 惰性初始化 这是因为我尝试获取的接口可能存在于尚未加载的 DLL 中。

(边注: 这在注册单个 DLL 时尤其重要,因为全局对象将在 regsvr32 进程,并且我不希望 DLL 在此过程中尝试获取另一个 DLL 的接口。)

例如,我的惰性初始化方法会执行如下操作:

CComPtr<IMyOtherObject>&
CGlobalSingleton::
GetMyOtherObject()
{
    // SNIP: Other code removed for clarity...

    if (! m_pMyOtherObject)
    {
        hr = pUnknown->QueryInterface(IID_IMyOtherObject,
            (void**) &m_pMyOtherObject);
    }

    return m_pMyOtherObject;
}

笔记: m_pMyOtherObject 是一个成员变量 CComPtr 类型。

延迟初始化可能与我的问题无关,但为了完整性我将其包括在内。

问题

我注意到,在某些情况下,当我的应用程序关闭时,我会得到失败的断言。但是,如果我更改代码来调用 QueryInterface() 每一个 我需要访问的时间 IID_IMyOtherOBject (而不是将其存储为成员变量)这会阻止断言。

在我看来,这是一个 COM 对象生命周期问题。我的假设是因为我是 storing 一个 COM 指针,在我指向的 COM 接口的销毁和我自己的指向它的指针之间需要有某种同步。

我的理解 CComPtr 类(我正在使用的)的优点是它消除了处理生命周期问题的很多麻烦(即。呼叫 AddRef()Release())。但它似乎不适用于我的情况。

谁能挑出我可能做错了什么?

其他提示

您会返回智能指针可能不会增加引用计数的参考。对不起,我会检查,但已经晚了这里。这是我的直觉,它适合你描述 - 看看拷贝构造函数但是CComPtr

希望帮助,

ķ

在黑暗中刺野:有没有可能是CGlobalSingleton可以被摧毁的之后CoUninitialize()被调用时,在任何情况下?如果是这样,和m_pMyOtherObject是因此也COM反初始化后销毁,它会导致访问冲突伊戈尔提到的另一种方式。

我怀疑问题出在你的但是CComPtr类的复制/赋值语义的理解;我不是特别熟悉,但是CComPtr,但以我的经验智能指针往往不工作,你可能期望他们的方式。首先,你应该阅读的但是CComPtr文件,确保你了解它是如何工作(它不会伤害看看源代码,要么)。你也可以尝试把一些断点中的AddRef()和Release()但是CComPtr的成员查看期间调用GetMyOtherObject(之后会发生什么),特别是如果你是临时存储的返回值,它超出范围。

听上去像 m_pMyOtherObject 当您关闭应用程序时仍然存在。除了复制构造函数问题 m_pMyOtherObject 应该是 CComPtr 或者 CGlobalSingleton 应该打电话 m_pMyOtherObjectRelease 销毁时的方法。

为了清楚起见进行了编辑。

编辑 刚刚做了一个快速测试,使用返回引用的函数没有遇到任何问题 CComPtr. 。虽然这有点不寻常,但它并没有导致任何引用计数问题。

我想扩展一下如果 m_pMyOtherObject 不是智能指针。在这种情况下,它永远不会被释放。让我告诉你原因:

  1. 您在某个指针上调用 QueryInterface。它将对该对象调用 AddRef。
  2. 您返回 CComPtr& CComPtr& 或裸接口指针。这在很大程度上是无关紧要的。不会发生引用计数操作(除非您将返回值分配给另一个 CComPtr,这将 AddRef 它。但由于 CComPtr 将通过调用 Release 来平衡它,所以这并不重要)。
  3. 最终的结果是要么 1 次调用 AddRef,0 次调用 Release,要么 2 次调用 AddRef,1 次调用 Release。换句话说,它们不平衡,并且存在参考泄漏。

为了避免这种情况,你需要像这样构建你的程序:

class CGlobalSingleton{

CComPtr<IMyOtherObject> m_spMyOtherObject;

IMyOtherObject* GetMyOtherObject()
{
    // SNIP: Other code removed for clarity...

    if (! m_spMyOtherObject)
    {
        //pUnknown gets AddRef'ed, but that's OK, m_spMyOtherObject will call release when CGlobalSingleton goes out of scope
        hr = pUnknown->QueryInterface(IID_IMyOtherObject,
            (void**) &m_spMyOtherObject);
    }

    return m_pMyOtherObject;
}
}
scroll top