在事件运行后释放Inventor



程序控制Autodesk Inventor,同时执行它应该执行的操作,即ZIP并将图形转换为所需的文件类型。

程序运行后,我可以使用Inventor,但它不允许我保存任何内容,而且我认为程序仍然锁定了Inventor。

我该如何释放它?

如果你需要更多信息,请告诉我。

编辑#1

仅供参考,我没有写这个程序,我对Autodesk Vault/Inventor这个奇妙但令人困惑的世界完全陌生。

这就是我假设Inventor被C#锁定的地方

m_inventorApp = System.Runtime.InteropServices.Marshal.GetActiveObject("Inventor.Application") as Inventor.Application;

然后在函数结束时,m_inventorApp被设置为null。

m_inventorApp = null;
m_inventorApp2 = null;

短版本

您的代码根本没有释放COM引用。使用Marshal.FinalReleaseComObject显式释放它,最好是在try/finally块中也不要将COM对象存储在字段中,尽可能晚地创建它们,并尽快释放它们,例如:

Inventor.Appication inventorApp=null;
try
{
inventorApp = (Inventor.Application)Marshal.GetActiveObject("Inventor.Application");
.....
}
finally
{
if(inventorApp !=null)
{
Marshal.FinalReleaseComObject(inventorApp);
}
}

使用FinalReleaseComObject而不是ReleaseComObject可以立即释放对象。

将字段或变量设置为null仅意味着COM引用对象可用于垃圾收集,它不会减少COM的引用计数或显式释放COM对象。

通过使用变量而不是字段,您可以确保没有任何悬空引用

解释

您使用的是COM自动化,而不是Autodesk Inventor特有的自动化。这是Windows上一种应用程序控制另一个应用程序的标准方式。COM早在.NET之前就构建好了,它使用引用计数而不是垃圾回收。NET本身作为";下一个";COM版本,然后在2002年发布时变得完全不同。COM已旧。

每次创建对COM对象的引用时,COM都会递增该对象的引用计数器。每次释放它时,引用计数器都会递减。只有当计数器达到0时,才会释放COM对象。这意味着您的代码必须确保计数器递减,否则对象将一直使用,直到垃圾回收器运行为止。

.NET通过运行时可调用包装器与COM组件协同工作。链接的文档解释了引用计数,引用计数是如何工作的,以及发布引用需要做什么。

调用Marshal.GetActiveObject时,将获得Inventor(或任何其他应用程序(对已在运行的COM服务器对象提供程序的引用。引用的计数器从1开始,每次创建新引用时都会增加。

每个客户端应用程序都必须显式递减引用计数器。在引用计数达到0之前,COM服务器对象和创建它的应用程序无法关闭。

为什么FinalReleaseComObject

当客户端请求对同一对象的多个引用时,它会用递增的计数器返回相同的引用。要真正释放一个对象,您必须根据请求多次释放该引用。这在Visual Basic 6和C++中造成了相当多的对象泄漏,尤其是当人们对引用不小心时。为了强制杀死一个对象,人们经常编写循环,在引用上重复调用Release,直到计数达到0。

当.NET发布时,方法ReleaseComObject只会将引用计数递减1。这导致了与VB6和C++相同的泄漏问题。当.NET Framework 2.0在2005年问世时,它引入了FinalReleaseComObject,它实际上自己完成了循环。当涉及多个线程时,情况会变得更糟,这意味着一个线程可以释放COM对象,而另一个线程仍在使用它

文档现在解释道:

只有在绝对需要ReleaseComObject时才使用它。如果要调用此方法以确保COM组件在确定的时间发布,请考虑改用FinalReleaseComObject方法。

FinalReleaseComObject将释放底层COM组件,无论它重新进入CLR的次数如何。每次COM组件重新进入CLR时,RCW的内部引用计数都会增加一。因此,您可以在循环中调用ReleaseComObject方法,直到返回的值为零。这实现了与FinalReleaseComObject方法相同的结果。

最新更新