簡體   English   中英

Inventor COM object 使用 Activator.CreateInstance() 創建時未發布

[英]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(); 沒有問題。

所以,左開過程的問題只出現在這個特定的組合中:

  1. 通過Activator.CreateInstance(InventorType);
  2. 用戶手動退出 Inventor

左打開的進程不再在 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM