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();
нет проблем.
Итак, проблема с левым открытым процессом возникает только в этой конкретной комбинации:
- запустить Inventor через
- пользователь выходит из 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-объект, как вы пытаетесь. Я рекомендую вам обернуть
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-диез