C++ – Problem with storing COM pointers in global singleton object

ccomglobal-variableslazy-evaluationobject-lifetime

Background

The application I am working with has several COM DLLs.

One of the COM DLLs has a global singleton object, which stores pointers to COM interfaces in other DLLs. Because it is a global singleton object, I have employed the lazy initialization idiom because it is possible that the interface I am trying to get a pointer to exists in a DLL which hasn't yet been loaded.

(Side-note: This is especially important when registering a single DLL, as the global objects will be constructed within the regsvr32 process, and I don't want the DLL to attempt to acquire an interface to another DLL during this process.)

For example, my lazy initialization method would do something like this:

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

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

    return m_pMyOtherObject;
}

NOTE: m_pMyOtherObject is a member variable of the CComPtr type.

The lazy initialization may not be relevant to my problem here, but I'm including it for completeness.

Problem

What I have noticed is that in some circumstances, I get failed assertions when my application shuts down. However, if I change my code to call QueryInterface() every time I need to access IID_IMyOtherOBject (rather than storing it as a member variable) this prevents the assertions.

This appears to me to be a COM object lifetime issue. My hypothesis is that because I am storing a COM pointer, there needs to be some sort of synchronisation between the destruction of the COM interface that I'm pointing to, and my own pointer to it.

My understanding of the CComPtr class (which I am using) is that it takes away a lot of the headaches of dealing with lifetime issues (i.e. calling AddRef() and Release()). But it doesn't appear to be working in my case.

Can anyone pick what I may be doing wrong?

Best Answer

Rather than implementing your own global singleton, look at using the IGlobalInterfaceTable interface instead. It is a singleton that is provided by the OS at the process level. Any of your DLLs can put their COM objects into the table, and the other DLLs can retreive them when needed. All you would need to implement on your part is a way for the DLLs to exchange the table's DWORD cookies with each other.

Related Topic