My problem is this: If Autodesk Inventor is not running, my app (console app) creates a new instance with Activator.CreateInstance(InventorType);
and uses it as a COM object. When my app does not quit Inventor but leaves it open and the user later quits it by hand there is still a process inventor.exe running in TaskManager which can only be killed in TaskManager. Curiously the problem only arises when these two things are combined. Whenever my app quits Inventor with InventorApp.Quit();
it is closed properly and there is no process left open.
If my app starts Inventor with Process.Start(..);
or the user starts Inventor before starting the app and then my app grabs Inventor with Marshal.GetActiveObject(ProgId);
there is no problem no matter if the app or the user quits Inventor.
If my app starts Inventor with Activator.CreateInstance(InventorType);
then leaves Inventor open, the app is closed and then restarted, it grabs Inventor with Marshal.GetActiveObject(..);
and then quits Inventor via InventorApp.Quit();
there is no problem.
So, the problem with the left open process only arises in this specific combination:
Activator.CreateInstance(InventorType);
The left open process is not in the Running Object Table anymore so it can't be handled as a COM object anymore and it has no visible UI, which means it can only be killed in TaskManager.
Using the 'bad combination' as described I even tried to call GC.WaitForPendingFinalizers(); GC.Collect();
GC.WaitForPendingFinalizers(); GC.Collect();
several times (I know this is bad but I am just trying everything) in different combinations and before and/or after Marshal.ReleaseComObject(invApp); Marshal.FinalReleaseComObject(invApp);
Marshal.ReleaseComObject(invApp); Marshal.FinalReleaseComObject(invApp);
. I even tried a minimal app which literally does nothing else. See below for the code.
So, what is Activator.CreateInstance(InventorType);
doing that is causing this? Is there any way to prevent this? Or is this a problem specific to Inventor?
Minimal app example:
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;
This is not specific for Inventor but for any COM object (Excel for example).
Usually I don't use this COM communication for production, because there are many vulnerabilities and some performance issues. I recommend you to use another workflow when possible. But to your question. You can't release this COM object as you try. I recommend you to wrap Inventor.Application
to some IDisposable
object and quit them in dispose method, when you create your own instance.
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);
}
}
}
}
I don't know if this is the best solution but it is a good start point.
I found only one issue. When user quit the console application by cross. In this case you can see this article how to solve this case. capture-console-exit-c-sharp
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.