C# で記述されたマネージ COM オブジェクトと、C++ (MFC および ATL) で記述されたネイティブ COM クライアントとシンクがあります。クライアントはオブジェクトを作成し、起動時にそのイベント インターフェイスに通知し、イベント インターフェイスから通知を取り消し、シャットダウン時にオブジェクトを解放します。問題は、COM オブジェクトが、ガベージ コレクションが実行されるまで解放されないシンクへの参照を持っていることです。ガベージ コレクションが実行されると、クライアントは既に破棄されているため、通常はアクセス違反が発生します。とにかくクライアントがシャットダウンしているので、おそらくそれほど大したことではありませんが、可能であればこれを適切に解決したいと考えています. シンク オブジェクトをよりタイムリーに解放するには、COM オブジェクトが必要ですが、COM オブジェクトがシンク オブジェクトと明示的に連携しないため、どこから始めればよいかわかりません。
私のCOMオブジェクト:
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);
}
}
}
クライアントは標準の MFC ダイアログ ベースのプログラムで、ATL のサポートが追加されています。私のシンククラス:
class CTestObjectEventsSink : public CComObjectRootEx<CComSingleThreadModel>, 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;
}
};
ダイアログクラスには次のメンバーがあります。
ITestObjectPtr m_TestObject;
CComObject<CTestObjectEventsSink>* m_TestObjectEventsSink;
DWORD m_Cookie;
OnInitDialog() で:
HRESULT hr = m_TestObject.CreateInstance(__uuidof(TestObject));
if(m_TestObject)
{
hr = CComObject<CTestObjectEventsSink>::CreateInstance(&m_TestObjectEventsSink);
if(SUCCEEDED(hr))
{
m_TestObjectEventsSink->AddRef(); // CComObject::CreateInstace() gives an object with a ref count of 0
hr = AtlAdvise(m_TestObject, m_TestObjectEventsSink, __uuidof(ITestObjectEvents), &m_Cookie);
}
}
OnDestroy() で:
if(m_TestObject)
{
HRESULT hr = AtlUnadvise(m_TestObject, __uuidof(ITestObjectEvents), m_Cookie);
m_Cookie = 0;
m_TestObjectEventsSink->Release();
m_TestObjectEventsSink = NULL;
m_TestObject.Release();
}