[英]Inventor COM object not released when created with Activator.CreateInstance()
我的問題是:如果 Autodesk Inventor 沒有運行,我的應用程序(控制台應用程序)使用Activator.CreateInstance(InventorType);
並將其用作 COM object。當我的應用程序沒有退出 Inventor 而是保持打開狀態並且用戶稍后手動退出時,仍然有一個進程inventor.exe在 TaskManager 中運行,它只能在 TaskManager 中被殺死。 奇怪的是,只有當這兩件事結合在一起時,問題才會出現。 每當我的應用程序使用InventorApp.Quit();
它已正確關閉,並且沒有任何進程處於打開狀態。
如果我的應用程序使用Process.Start(..);
或者用戶在啟動應用程序之前啟動 Inventor,然后我的應用程序使用Marshal.GetActiveObject(ProgId);
無論應用程序還是用戶退出 Inventor 都沒有問題。
如果我的應用使用Activator.CreateInstance(InventorType);
然后讓 Inventor 打開,應用程序關閉然后重新啟動,它使用Marshal.GetActiveObject(..);
然后通過InventorApp.Quit();
沒有問題。
所以,左開過程的問題只出現在這個特定的組合中:
Activator.CreateInstance(InventorType);
左打開的進程不再在 Running Object Table 中,因此它不能再作為 COM object 處理,並且它沒有可見的 UI,這意味着它只能在 TaskManager 中被殺死。
使用描述的“錯誤組合”我什至嘗試調用GC.WaitForPendingFinalizers(); GC.Collect();
GC.WaitForPendingFinalizers(); GC.Collect();
在Marshal.ReleaseComObject(invApp); Marshal.FinalReleaseComObject(invApp);
Marshal.ReleaseComObject(invApp); Marshal.FinalReleaseComObject(invApp);
. 我什至嘗試了一個最小的應用程序,它實際上什么都不做。 請參閱下面的代碼。
那么,什么是Activator.CreateInstance(InventorType);
這樣做會導致這個嗎? 有什么辦法可以防止這種情況發生嗎? 或者這是 Inventor 特有的問題?
最小的應用程序示例:
Inventor.Application invApp = null;
string ProgId = "Inventor.Application";
try
{
invApp = (Inventor.Application)Marshal.GetActiveObject(ProgId);
}
catch (Exception e1)
{
try
{
Type InventorType = Type.GetTypeFromProgID(ProgId);
invApp = (Inventor.Application)Activator.CreateInstance(InventorType);
}
catch (Exception e2)
{
Console.WriteLine(e1);
Console.WriteLine(e2);
}
}
invApp = invApp as Inventor.Application;
invApp.Visible = true;
Console.Write("Quit Inventor? (y/n) ");
string quit = Console.ReadLine();
if (quit == "y")
{
invApp.Quit();
}
// desperately trying to release the COM object ...
GC.WaitForPendingFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
if (invApp != null)
{
Marshal.ReleaseComObject(invApp);
Marshal.FinalReleaseComObject(invApp);
}
GC.WaitForPendingFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
if (invApp != null)
{
Marshal.ReleaseComObject(invApp);
Marshal.FinalReleaseComObject(invApp);
}
GC.WaitForPendingFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
invApp = null;
這不是特定於 Inventor,而是特定於任何 COM object(例如 Excel)。
通常我不會將這個 COM 通信用於生產,因為存在很多漏洞和一些性能問題。 我建議您盡可能使用其他工作流程。 但是對於你的問題。 你不能隨便釋放這個COM object。 我建議您在創建自己的實例時將Inventor.Application
包裝到一些IDisposable
object 並在 dispose 方法中退出它們。
static void Main(string[] args)
{
InventorTest();
//Waiting for dispose message
//Console.ReadKey();
}
private static void InventorTest()
{
using (var invProvider = new InventorDisposableProvider())
{
var invApp = invProvider.InventorApp;
invApp.Visible = true;
Console.Write("Quit Inventor? (y/n) ");
string quit = Console.ReadLine();
if (quit == "y")
{
invApp.Quit();
}
}
}
class InventorDisposableProvider : IDisposable
{
private Application invApp;
private bool startedByMe = false;
/// <summary>
/// Gets running or start new instance of Inventor
/// </summary>
public Application InventorApp
{
get
{
if (invApp == null) GetInventorApp();
return invApp;
}
}
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
public void Dispose()
{
if (startedByMe && invApp != null)
{
invApp .Quit();
Console.WriteLine("Quit");
}
}
private void GetInventorApp()
{
string ProgId = "Inventor.Application";
try
{
invApp = (Inventor.Application)Marshal.GetActiveObject(ProgId);
startedByMe = false;
}
catch (Exception e1)
{
try
{
Type InventorType = Type.GetTypeFromProgID(ProgId);
invApp = (Inventor.Application)Activator.CreateInstance(InventorType);
startedByMe = true;
}
catch (Exception e2)
{
Console.WriteLine(e1);
Console.WriteLine(e2);
}
}
}
}
我不知道這是否是最好的解決方案,但它是一個很好的起點。
我只發現一個問題。 當用戶通過交叉退出控制台應用程序時。 在這種情況下,您可以查看本文如何解決這種情況。 捕獲控制台退出-c-sharp
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.