我有一个使用C#编写的托管COM对象以及一个使用C++(MFC和ATL)编写的本地COM客户端和接收器。在启动时,客户端创建该对象并通知其事件接口,并在关闭时取消通知其事件接口并释放该对象。问题在于,COM对象具有对接收器的引用,该引用直到垃圾回收运行时才被释放,在此时,客户端已被撤销,因此通常会导致访问冲突。这可能并不是重要的事情,因为客户端无论如何都会关闭,但如果可能的话,我想优雅地解决这个问题。我需要我的COM对象更及时地释放我的接收器对象,但我不知道从何处开始,因为我的COM对象没有显式与接收器对象一起工作。
客户端是一个标准的基于MFC对话框程序,具有对ATL的支持。我的sink类:
我在我的对话框类中有以下成员:
在OnInitDialog()函数中:
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的支持。我的sink类:
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();
}