最近我在做一个小项目,它涉及一个 DLL 模块(用 C# 创建)并且我需要在我的应用程序中使用它(用非托管 C++ 编写)为此,我使用了 ATL/COM。
我注意到即使我使用的是 _com_ptr_t在我用于处理我的核心 COM 接口(interface)的 C++ 应用程序中,C# 对象的析构函数仅在我的应用程序关闭时被调用。
让我给你一些资源让事情更清楚一点:
我的一些 C# 代码:
[ComVisible(true)]
[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIDispatch)]
public interface ITestCOM
{
[DispId(1)]
void Connect([In, MarshalAs(UnmanagedType.U2)] ushort value);
}
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
[ComSourceInterfaces(typeof(ITestCOMEvents))]
public partial class TestCOM : ITestCOM
{
...
~TestCOM()
{
MessageBox.Show("DESTRUCTOR");
}
...
public void Connect(ushort value)
{
...
}
}
我正在使用如下方式创建 .tlb 文件: “RegAsm.exe TestCOM.dll/tlb:Test.tlb/codebase”
在我的 C++ 头文件中我有:
#import "C:\...\mscorlib.tlb"
#import "......\TestCOM.tlb" named_guids exclude("ISupportErrorInfo")
#include <afxdisp.h>
#include <atlcom.h>
class Unit : public ::IDispEventSimpleImpl<0, Unit, &__uuidof(TestCOM::ITestCOMEvents)>
{
public:
BEGIN_SINK_MAP(Unit)
SINK_ENTRY_INFO(0, __uuidof(TestCOM::ITestCOMEvents), 0x1, OnEventCallback, &OnEventCallbackDef)
END_SINK_MAP()
...
private
TestCOM::ITestCOMPtr mTestCOM;
// NOTE: This would be the same as "_com_ptr_t<_com_IIID<TestCOM::ITestCOM, &__uuidof(TestCOM::ITestCOM)> > mTestCOM;"
}
我的 C++ 源文件是这样创建“mTestCOM”的:
mTestCOM.CreateInstance(TestCOM::CLSID_TestCOM)
基本上就是这样。我可以像这样使用我的任何 C#“TestCOM”对象的函数:
mTestCOM->Connect(7);
问题是: 为什么我的 C# TestCOM 对象的析构函数仅在我的应用程序关闭时调用,而不是在我的 C++“单元”对象被销毁时调用?
最佳答案
虽然我不熟悉 C# 和 COM 集成,但我知道 C# 中的析构函数与 C++ 中的析构函数非常不同。 C# 对象是内存管理和垃圾收集的。这意味着在对象停止被其所属的应用程序引用并变得“无法访问”之后的某个时刻,垃圾收集器将销毁它。
所以第一个重要的事情是一个对象被放弃和垃圾收集器销毁它之间的延迟是不确定的......它会发生在“ future 的某个时刻”,这很可能是在应用程序终止的那一刻.
其次,垃圾收集器并不总是在运行。有“内存压力”的概念,当您的应用程序正在分配大块内存并且可用的可用内存即将耗尽时......此时,垃圾收集器将触发以清除旧的,无法访问的对象。如果您的应用程序没有分配大量内存,它就不会遭受任何内存压力,垃圾收集器也不需要运行。
如果你想确定性地清理一些托管对象的资源,你需要使用像IDisposable
这样的东西。界面并调用Dispose
显式方法。
关于在 C++ 中使用 COM/ATL 接口(interface)时,C# 对象未被销毁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13381413/