@fieldguy 's reply (Message 6) provided enough technical information, I think.
However, I wish you provided more information on why you need to start multiple AutoCAD (and its verticals) instances from a stand-alone desktop EXE. If the solution is meant for user working in front of computer, I can hardly see it is user friendly: running 2 app for a job task (the win form app plus one automated ACAD instance) is bad enough in most cases; running 3 or more? I'd consider it is disaster. I'd avoid this kind of solution at all cost.
With that said, as @fieldguy 's advice, I quickly built a console EXE app to just prove how to do what you want:
The app does following:
1. Start 2 instance of AutoCAD: vanilla AutoCAD2020 and C3D 2021. They are started with Process.Start() with proper arguments, which include switch "/product", so that the Acad instance is started as the desired Acad vertical.
2. Use ROT (Running Object Table) to identify different "Product" of the Acad instance and obtain the COM objects back, which could be cast into AcadApplication for early binding. But I'd keep the COM object as dynamic for late binding.
The code for the console app:
using System;
using System.Collections.Generic;
using System.Diagnostics;
namespace GetMultiComInstances
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Press Enter to continue...");
Console.ReadLine();
var clsIds = StartAutoCADInstances();
// Wait for the AutoCADs get fully started before searching the ROT
// If the code to go through ROT runs with the different Acad instance
// are already there, there is no need to wait.
System.Threading.Thread.Sleep(20000);
var instances = RotUtils.GetAcadInstanceComObjects(clsIds);
if (instances!=null && instances.Count>0)
{
foreach (var ins in instances)
{
// Get a late bound AcadApplication object
dynamic acad = ins.Item2;
// For example, from acad.Caption property,
// one can tell the acad COM object is AutoCAD, or C3D
Console.WriteLine($"Instance: {ins.Item1}; Product: {acad.Caption}");
}
}
Console.WriteLine("Press Enter to exit...");
Console.ReadLine();
}
private static List<string> StartAutoCADInstances()
{
var clsIds = new List<string>();
var clsId = StartPlainAcad2020();
if (!string.IsNullOrEmpty(clsId)) clsIds.Add(clsId);
clsId = StartC3D2021();
if (!string.IsNullOrEmpty(clsId)) clsIds.Add(clsId);
return clsIds;
}
private static string StartPlainAcad2020()
{
try
{
Console.WriteLine("Starting AutoCAD 2020...Please wait...");
var process = Process.Start(
@"C:\Program Files\Autodesk\AutoCAD 2020\acad.exe",
"\"C:\\Temp\\Test01.dwg\" /product ACAD /language \"en - US\"");
process.WaitForInputIdle();
Console.WriteLine("AutoCAD 2020 started!");
Type t = Type.GetTypeFromProgID("AutoCAD.Application.23.1");
return t.GUID.ToString();
}
catch
{
Console.WriteLine("Starting AutoCAD 2020 failed!");
return null;
}
}
private static string StartC3D2021()
{
try
{
Console.WriteLine("Starting C3D 2021...Please wait...");
var process = Process.Start(
@"C:\Program Files\Autodesk\AutoCAD 2021\acad.exe",
"\"C:\\Temp\\Test02.dwg\" /ld \"C:\\Program Files\\Autodesk\\AutoCAD 2021\\AecBase.dbx\" " +
"/p \"<<C3D_Metric>>\" /product \"C3D\" /language \"en - US\"");
process.WaitForInputIdle();
Console.WriteLine("C3D 2021 started!");
Type t = Type.GetTypeFromProgID("AutoCAD.Application.24");
return t.GUID.ToString();
}
catch
{
Console.WriteLine("Starting C3D 2021 failed!");
return null;
}
}
}
}
The code of RotUtils class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.Text;
using System.Threading.Tasks;
namespace GetMultiComInstances
{
public class RotUtils
{
[DllImport("ole32.dll")]
private static extern void CreateBindCtx(int reserved, out IBindCtx ppbc);
[DllImport("ole32.dll")]
private static extern int GetRunningObjectTable(int reserved, out IRunningObjectTable prot);
public static List<Tuple<string, object>> GetAcadInstanceComObjects(List<string> classIds)
{
IRunningObjectTable rot;
IEnumMoniker enumMoniker;
GetRunningObjectTable(0, out rot);
if (rot == null) return null;
rot.EnumRunning(out enumMoniker);
if (enumMoniker == null) return null;
IntPtr pNumFetched = new IntPtr();
IMoniker[] monikers = new IMoniker[1];
List<Tuple<string, object>> instances = new List<Tuple<string, object>>();
// go through all entries and identifies app instances
while (enumMoniker.Next(1, monikers, pNumFetched) == 0)
{
IBindCtx bindCtx;
CreateBindCtx(0, out bindCtx);
if (bindCtx == null) continue;
string displayName;
monikers[0].GetDisplayName(bindCtx, null, out displayName);
Console.WriteLine("Display Name: {0}", displayName);
foreach (var clsId in classIds)
{
if (displayName.ToUpper().Contains(clsId.ToUpper()))
{
object comObject;
rot.GetObject(monikers[0], out comObject);
if (comObject != null)
{
instances.Add(new Tuple<string, object>(displayName, comObject));
}
}
}
}
return instances;
}
}
}
Hope this helps. Again, I strongly doubt that running a desktop exe to automate 2 or more instance of AutoCAD is a good solution in most cases, if not all cases.