Opening AutoCAD and AutoCAD Electrical Simultaneouly using C#

Opening AutoCAD and AutoCAD Electrical Simultaneouly using C#

thanigai1311
Participant Participant
2,146 Views
10 Replies
Message 1 of 11

Opening AutoCAD and AutoCAD Electrical Simultaneouly using C#

thanigai1311
Participant
Participant

Hi,

I have been working on creating a Windows application (in C#) to open some drawings in both AutoCAD and AutoCAD electrical.
As of now, I am able to open the last used AutoCAD application
like if I have opened and closed AutoCAD, the windows application will open AutoCAD
If I have opened and closed AutoCAD electrical, the windows application will open AutoCAD Electrical

 

I am using the Marshal method and create instance method to try and open both.

My question is that, is it possible to open both AutoCAD and AutoCAD Electrical simultaneouly from the windows application?

 

Thanks in advance.

0 Likes
Accepted solutions (1)
2,147 Views
10 Replies
Replies (10)
Message 2 of 11

fieldguy
Advisor
Advisor
0 Likes
Message 3 of 11

thanigai1311
Participant
Participant

Hi
Thanks for the reply but I want to open them from a Windows application(WinForm) using C#

0 Likes
Message 4 of 11

fieldguy
Advisor
Advisor

i understand that you want to start autocad from a winform - that is the first line in your post. you said "I am using the Marshal method and create instance method to try and open both". show your code for that. 

0 Likes
Message 5 of 11

thanigai1311
Participant
Participant

Hi
Here I attach the method that used to call and open a new instance of the application

AcadApplication acadApp = null
public AcadApplication TryOpenAcadapplication()
            try
            {
                acadApp  = (AcadApplication)Marshal.GetActiveObject(AutoCAD.Application);
            }
            catch
            {
                try
                {
                    acadApp = (AcadApplication)Activator.CreateInstance(Type.GetTypeFromProgID(AutoCAD.Application));
                   acadApp.Visible = true;
                }
                catch (System.Exception ex)
                {
                     MessageBox.Show(ex.ToString());
                     MessageBox.Show(AutoCAD Application cannot be opened)
                }
            }
0 Likes
Message 6 of 11

fieldguy
Advisor
Advisor

sorry i missed "Marshal" in your original post. the link i provided works with the System.Diagnostics.Process.Start method - something like this:

System.Diagnostics.Process.Start (@"C:\Program Files\Autodesk\AutoCAD 2020\acad.exe", "/product ACAD /language \"en-US\"") ;

if you want to try that check the "Target" value in the desktop icons if you have them.

i have never used interop. search this forum for "gettypefromprogid".

there is also >>this link<< for multiple instances but not sure if you need that.   

Message 7 of 11

jtoverka
Advocate
Advocate

The startup application is determined by the registry. There is a post here that may be what you need, or at least to guide you in the right direction:

AutoCAD DWG Launcher Registry 

 

If you do find the solution, please post it for everyone to see.

0 Likes
Message 8 of 11

norman.yuan
Mentor
Mentor
Accepted solution

@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.

 

Norman Yuan

Drive CAD With Code

EESignature

Message 9 of 11

Alexander.Rivilis
Mentor
Mentor

@norman.yuan 

If versions of AutoCAD and AutoCAD "vertical" (AE, C3D, etc) are equal (for example 2020 and 2020) - it is impossible to distinguish they in ROT - ROT has only one copy of AutoCAD.

Відповідь корисна? Клікніть на "ВПОДОБАЙКУ" цім повідомленням! | Do you find the posts helpful? "LIKE" these posts!
Находите сообщения полезными? Поставьте "НРАВИТСЯ" этим сообщениям!
На ваше запитання відповіли? Натисніть кнопку "ПРИЙНЯТИ РІШЕННЯ" | Have your question been answered successfully? Click "ACCEPT SOLUTION" button.
На ваш вопрос успешно ответили? Нажмите кнопку "УТВЕРДИТЬ РЕШЕНИЕ"


Alexander Rivilis / Александр Ривилис / Олександр Рівіліс
Programmer & Teacher & Helper / Программист - Учитель - Помощник / Програміст - вчитель - помічник
Facebook | Twitter | LinkedIn
Expert Elite Member

0 Likes
Message 10 of 11

norman.yuan
Mentor
Mentor

@Alexander.Rivilis 

Yes, you are right. My code does not suggest that the COM objects returned from ROT search can be recognized as different verticals of AutoCAD. They are just COM instances of AcadApplication for each running AutoCAD session. That is why I mention the the code comment to use "acad.Caption" would provide the hint of vertical product name (well, unless the running AutoCAD has custom app that manipulate the main window's caption, as AutoCAD .NET API allows it).

 

So, to make sure which vertical the COM object is, it may require further work, such as trapping exceptions by invoke vertical-only object... But for the OP's original question, if he/she already knows which products to start/or are already started, and there is not code to manipulate the app's caption, it might be good enough to just tell from the Caption property of AcadApplication object.

Norman Yuan

Drive CAD With Code

EESignature

0 Likes
Message 11 of 11

thanigai1311
Participant
Participant

Thanks for the solution @norman.yuan,
I think this will solve my problem.
and once again thanks for the Input

0 Likes