Tôi có đối tượng COM được quản lý được viết bằng C# và trình khách COM gốc và chìm được viết bằng C++ (MFC và ATL). Máy khách tạo đối tượng và tư vấn cho giao diện sự kiện của nó khi khởi động và các unadvises từ giao diện sự kiện của nó và giải phóng đối tượng lúc tắt máy. Vấn đề là đối tượng COM có một tham chiếu đến bồn rửa mà không được phát hành cho đến khi thu gom rác chạy, lúc đó máy khách đã bị rách và do đó thường dẫn đến vi phạm truy cập. Nó có lẽ không phải là một thỏa thuận lớn vì khách hàng đang đóng cửa, nhưng tôi muốn giải quyết điều này một cách duyên dáng nếu có thể. Tôi cần đối tượng COM của tôi để giải phóng đối tượng chìm của tôi một cách kịp thời hơn, và tôi không thực sự biết bắt đầu từ đâu đối tượng COM của tôi không làm việc với đối tượng sink một cách rõ ràng.Làm thế nào để quản lý tuổi thọ đối tượng khi làm việc với COM interop?
đối tượng COM của tôi:
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);
}
}
}
Các khách hàng là một chương trình MFC thoại dựa trên tiêu chuẩn, với hỗ trợ thêm cho ATL. lớp chìm của tôi:
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;
}
};
tôi có các thành viên sau đây trong lớp thoại của tôi:
ITestObjectPtr m_TestObject;
CComObject<CTestObjectEventsSink>* m_TestObjectEventsSink;
DWORD m_Cookie;
Trong 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);
}
}
Trong 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();
}
Có vẻ như tôi đang quên m_TestObjectEventsSink-> Release(). Nó không phải là tự động kể từ khi bạn lưu trữ một con trỏ đến CComObject <>, bạn có thể chỉ bị rò rỉ nó. Không chắc tại sao điều đó lại cần thiết. –
Rất tiếc, xin lỗi. Quên về những điều đó, nhưng hiệu ứng cũng giống như CComObject :: CreateInstance() cung cấp cho bạn một đối tượng với số lượng ref là 0. Tôi sẽ cập nhật câu hỏi bất kể. – Luke
CComObject :: CreateInstance() cung cấp cho bạn một đối tượng với số lượng ref là 0; đó là trách nhiệm của bạn đối với AddRef() nó. – Luke