By Adam Nagy
When running multiple instances of Inventor (or AutoCAD, Microsoft Excel, etc) then even though the ROT (Running Objects Table) lists all the running instances, they will all return the same Inventor.Application object that is returned by GetActiveObject as well - i.e. the first Inventor instance. See comments of this blog post:
http://adndevblog.typepad.com/autocad/2013/12/accessing-com-applications-from-the-running-object-table.html
The ROT also returns the currently open documents (Inventor.Document object) and those have the correct COM reference. So from those you can find the various Inventor.Application objects. Of course this only works for the Inventor instances which have documents open in them - and those documents need to be unique. E.g. if in Inventor instance #2 I open "mypart.ipt" then I also open the same file in Inventor instance #3 then that document will only have a single reference in the ROT and that will reference Inventor instance #2. I won't be able to access Inventor instance #3.
If you are trying to access the Inventor instance that you create through CreateProcess then one workaround is to create a copy of a template document with a unique name and open that in Inventor.
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
namespace InventorConsoleAppCSharp
{
class Program
{
[DllImport("ole32.dll")]
static extern int CreateBindCtx(
uint reserved,
out IBindCtx ppbc);
[DllImport("ole32.dll")]
public static extern void GetRunningObjectTable(
int reserved,
out IRunningObjectTable prot);
// Requires Using System.Runtime.InteropServices.ComTypes
// Get all running instance by querying ROT
private static object GetInventorApplicationWithWindowHandle(IntPtr hwnd)
{
// get Running Object Table ...
IRunningObjectTable Rot = null;
GetRunningObjectTable(0, out Rot);
if (Rot == null)
return null;
// get enumerator for ROT entries
IEnumMoniker monikerEnumerator = null;
Rot.EnumRunning(out monikerEnumerator);
if (monikerEnumerator == null)
return null;
monikerEnumerator.Reset();
IntPtr pNumFetched = new IntPtr();
IMoniker[] monikers = new IMoniker[1];
// go through all entries and identifies app instances
while (monikerEnumerator.Next(1, monikers, pNumFetched) == 0)
{
IBindCtx bindCtx;
CreateBindCtx(0, out bindCtx);
if (bindCtx == null)
continue;
string displayName;
monikers[0].GetDisplayName(bindCtx, null, out displayName);
System.Console.WriteLine(displayName);
object ComObject;
Rot.GetObject(monikers[0], out ComObject);
if (ComObject == null)
continue;
try
{
dynamic invDoc = ComObject;
if (new IntPtr(invDoc.Parent.MainFrameHWND) == hwnd)
{
// The parent of the document is the Application
return invDoc.Parent;
}
}
catch { }
}
return null;
}
static void Main(string[] args)
{
// Create document with unique name
string fileName = "C:\\temp\\" + Guid.NewGuid().ToString() + ".ipt";
System.IO.File.Copy(
"C:\\temp\\Gusset2013.ipt",
fileName);
// Start Inventor
Process process = Process.Start(
@"C:\Program Files\Autodesk\Inventor 2016\Bin\Inventor.exe",
"\"" + fileName + "\"");
// Wait until Inventor is fully ready
process.WaitForInputIdle();
while (process.MainWindowTitle == "")
{
process.Refresh();
System.Threading.Thread.Sleep(1000);
}
// Get all the Inventor.Application objects
// registered in the ROT
// ROT = Running Objects Table
Inventor.Application app = null;
for (; app == null; System.Threading.Thread.Sleep(1000))
{
// Find the Inventor.Application object with
// the correct window handle
app = GetInventorApplicationWithWindowHandle(process.MainWindowHandle)
as Inventor.Application;
}
Console.WriteLine("Found Inventor.Application object with title:\n" + app.Caption);
// Let's close file and delete it
app.Documents.get_ItemByName(fileName).Close();
System.IO.File.Delete(fileName);
// Wait for user to finish
Console.WriteLine("Press key to exit");
Console.ReadKey();
}
}
}