Note that there are some explanatory texts on larger screens.

plurals
  1. POHow to manage object lifetime when working with COM interop?
    text
    copied!<p>I have a managed COM object written in C# and a native COM client and sink written in C++ (MFC and ATL). The client creates the object and advises to its event interface at startup, and unadvises from its event interface and releases the object at shutdown. The problem is that the COM object has a reference to the sink which is not released until garbage collection runs, at which point the client is already torn down and thus usually results in an access violation. It's probably not that big of a deal since the client is shutting down anyway, but I would like to resolve this gracefully if possible. I need my COM object to release my sink object in a more timely manner, and I don't really know where to start since my COM object doesn't work with the sink object explicitly.</p> <p>My COM object:</p> <pre><code>public delegate void TestEventDelegate(int i); [ComVisible(true)] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] public interface ITestObject { int TestMethod(); void InvokeTestEvent(); } [ComVisible(true)] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] public interface ITestObjectEvents { void TestEvent(int i); } [ComVisible(true)] [ClassInterface(ClassInterfaceType.None)] [ComSourceInterfaces(typeof(ITestObjectEvents))] public class TestObject : ITestObject { public event TestEventDelegate TestEvent; public TestObject() { } public int TestMethod() { return 42; } public void InvokeTestEvent() { if (TestEvent != null) { TestEvent(42); } } } </code></pre> <p>The client is a standard MFC dialog-based program, with added support for ATL. My sink class:</p> <pre><code>class CTestObjectEventsSink : public CComObjectRootEx&lt;CComSingleThreadModel&gt;, public ITestObjectEvents { public: BEGIN_COM_MAP(CTestObjectEventsSink) COM_INTERFACE_ENTRY_IID(__uuidof(ITestObjectEvents), ITestObjectEvents) END_COM_MAP() HRESULT __stdcall raw_TestEvent(long i) { return S_OK; } }; </code></pre> <p>I have the following members in my dialog class:</p> <pre><code>ITestObjectPtr m_TestObject; CComObject&lt;CTestObjectEventsSink&gt;* m_TestObjectEventsSink; DWORD m_Cookie; </code></pre> <p>In OnInitDialog():</p> <pre><code>HRESULT hr = m_TestObject.CreateInstance(__uuidof(TestObject)); if(m_TestObject) { hr = CComObject&lt;CTestObjectEventsSink&gt;::CreateInstance(&amp;m_TestObjectEventsSink); if(SUCCEEDED(hr)) { m_TestObjectEventsSink-&gt;AddRef(); // CComObject::CreateInstace() gives an object with a ref count of 0 hr = AtlAdvise(m_TestObject, m_TestObjectEventsSink, __uuidof(ITestObjectEvents), &amp;m_Cookie); } } </code></pre> <p>In OnDestroy():</p> <pre><code>if(m_TestObject) { HRESULT hr = AtlUnadvise(m_TestObject, __uuidof(ITestObjectEvents), m_Cookie); m_Cookie = 0; m_TestObjectEventsSink-&gt;Release(); m_TestObjectEventsSink = NULL; m_TestObject.Release(); } </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload