COM-объект Inventor не освобождается при создании с помощью Activator.CreateInstance()

Моя проблема заключается в следующем: если Autodesk Inventor не запущен, мое приложение (консольное приложение) создает новый экземпляр и использует его как COM-объект. Когда мое приложение не выйдет Inventor , но оставляет его открытым и впоследствии пользователь завершает его стороны , есть еще процесс inventor.exe работает в TaskManager , которые могут быть убиты только в TaskManager. Любопытно, что проблема возникает только при сочетании этих двух вещей. Каждый раз, когда мое приложение закрывается из Inventor, оно закрывается должным образом, и ни один процесс не остается открытым.

Если мое приложение запускает Inventor с Process.Start(..); или пользователь запускает Inventor перед запуском приложения, а затем мое приложение захватывает Inventor с помощью Marshal.GetActiveObject(ProgId); Нет проблем, независимо от того, закрывает ли приложение Inventor приложение или пользователь.

Если мое приложение запускает Inventor с помощью, а затем оставляет Inventor открытым, приложение закрывается, а затем перезапускается, оно захватывает Inventor с помощью Marshal.GetActiveObject(..); а затем выйти из Inventor через InventorApp.Quit(); нет проблем.

Итак, проблема с левым открытым процессом возникает только в этой конкретной комбинации:

  1. запустить Inventor через
  2. пользователь выходит из Inventor вручную

Левый открытый процесс больше не находится в таблице запущенных объектов, поэтому он больше не может обрабатываться как COM-объект, и у него нет видимого пользовательского интерфейса, что означает, что его можно убить только в TaskManager.

Используя описанную «плохую комбинацию», я даже попытался назвать GC.WaitForPendingFinalizers(); GC.Collect(); несколько раз (я знаю, что это плохо, но я просто все пробую) в разных комбинациях и до и / или после 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;

1 ответ

Это относится не только к Inventor, но и к любому COM-объекту (например, Excel).

Обычно я не использую это COM-соединение для производства, потому что есть много уязвимостей и некоторые проблемы с производительностью. Я рекомендую вам по возможности использовать другой рабочий процесс. Но к твоему вопросу. Вы не можете освободить этот COM-объект, как вы пытаетесь. Я рекомендую вам обернуть некоторым 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-диез

Другие вопросы по тегам