Launching AutoCAD from a .NET application

This topic has been raised a few times, and Adam Nagy, from our DevTech EMEA team, sent a technical response recently with code that I decided to use as the basis for this post.

Developers typically want to either integrate functionality into AutoCAD (using its plug-in architecture to add commands, user-interface elements, objects, etc.), or to drive it, automating common tasks. Clearly the line can get blurred between these two areas, but today I'm going to focus on the second category.

To help with later explanations, I'd like to introduce two types of application interaction:

Out-of-process

In this situation we have two separate executables trying to communicate. Imagine you have an EXE and you want to drive AutoCAD. You need to find some way to launch AutoCAD and communicate with it – typically using COM or, before that, DDE. The communication is, by definition, done via Inter-Process Communication (IPC), which is a very inefficient way to send large chunks of data. This is why old ADS and external VB applications ran (or run) so slowly.

In-process

When your code is packaged inside a DLL (whether an ActiveX DLL defined in VB6, an ObjectARX module or a .NET assembly), the communication with the host process (AutoCAD) is much more efficient – data structures can be passed by pointer or reference rather than squirting the information through the inefficient marshalling of IPC.

Most of AutoCAD's current APIs are designed to be used "in-process" – this includes LISP, ObjectARX and AutoCAD's .NET API. Given the availability of .NET Remoting, people often hope or expect AutoCAD to be drivable via .NET "out-of-process", but this is not how the managed API was designed: it is really a wrapper on top of ObjectARX, whose performance is based on direct access to objects via pointers, and this simply does not extend to work across process boundaries. One of the great features of COM Automation is that it was designed to work either out-of-process (from an external EXE) or in-process (from VBA or by calling GetInterfaceObject() to load a VB6 ActiveX DLL). This is still the best way to drive AutoCAD from an external executable.

I generally recommend not trying to pass too much information across the process boundary: if you need to drive AutoCAD from an external executable, simply launch it (or connect to a running instance, if that's an option) and then load an in-process module to do the heavy lifting from within AutoCAD's process space.

The following code shows how to do just that, using C#. It tries to connect to a running instance of AutoCAD (this is optional – you can easily adjust the code only to launch AutoCAD), and failing that launches it. Once there's a running instance we make it visible and run a custom command. My recommendation is to set up demand-loading for your application – either to load it on AutoCAD startup or when a command is invoked – and then to run a command defined in your module.

You will need to add a reference to the "AutoCAD Type Library" from your application, as well as including these assembly references:

using System;

using System.Runtime.InteropServices;

using Autodesk.AutoCAD.Interop;

This C# code can be added to an "on-click" event handler for a button (for example) or another function that makes sense in the context of your application.

  // "AutoCAD.Application.17" uses 2007 or 2008,

  //  whichever was most recently run

  // "AutoCAD.Application.17.1" uses 2008, specifically

  const string progID = "AutoCAD.Application.17.1";

  AcadApplication acApp = null;

  try

  {

    acApp =

      (AcadApplication)Marshal.GetActiveObject(progID);

  }

  catch

  {

    try

    {

      Type acType =

        Type.GetTypeFromProgID(progID);

      acApp =

        (AcadApplication)Activator.CreateInstance(

          acType,

          true

        );

    }

    catch

    {

      MessageBox.Show(

        "Cannot create object of type \"" +

        progID + "\""

      );

    }

  }

  if (acApp != null)

  {

    // By the time this is reached AutoCAD is fully

    // functional and can be interacted with through code

    acApp.Visible = true;

    acApp.ActiveDocument.SendCommand("_MYCOMMAND ");

  }

One response to “Launching AutoCAD from a .NET application”

  1. Hi Kean,

    After AutoCAD has launched, I often have a need to determine the "Start In" directory specified in the shortcut (Right-click AutoCAD shortcut, Properties, Start in). Is there a way to determine what that directory is? I'm thinking I can use the path of the active drawing (either Drawing1 or the drawing they double-clicked on). Is that a fool-proof way?

    Thanks in advance for your help,
    -Danny

  2. Hi Kean
    Your notes at the top of the code make reference to the version of Autocad to run, but is there any way of passing through the profile to activate?. Many people have 3rd party apps that rely on profiles to ensure the correct menus etc are loaded. Some automation tasks will need the correct profiles loaded (in order to activate any custom object handlers)

  3. Danny -

    Please see this post.

    Greg -

    COM doesn't allow launching of a process with command-line arguments, as far as I'm aware, but you can use another approach to the launch AutoCAD to meet this need. I'll make this the topic of my next post.

    Thank you both for your comments!

    Regards,

    Kean

  4. Hi Kean, Happy Holidays.

    Regarding:

    Type acType = Type.GetTypeFromProgID(progID);
    acApp = (AcadApplication)Activator.CreateInstance(acType,true);

    I was just wondering if you may have come across any problems using the standard means of creating a new instance of AutoCAD and getting its AcadApplication object, e.g.,

    AcadApplication acApp = new AcadApplication();

    The AcadApplication's new() constructor internally calls Activator.CreateInstance() for you, and calling that usually starts up a new instance of AutoCAD.

  5. No specific reasons - that's just the code I inherited to do this.

    Happy Holidays to you, too, Tony.

    Kean

  6. Greg -

    Here's the post that looks at launching AutoCAD with a specific profile.

    Cheers,

    Kean

  7. Hi Kean,

    i will launch AutoCAD from an existing ProcessID in C#. The existing ProcessID was Written in the Registry from another C++ ObjectARX Application.
    Now i must linked at this Process, how can i make this.

  8. Hi Dirk,

    Do you mean ProcessID or ProgID?

    I'd recommend submitting this question via the ADN website, if you're a member.

    Regards,

    Kean

  9. Hi Kean,

    Is there a way of either passing parameters with SendCommand or directly calling methods in the NETLOAD'ed dll?

    Under VB6 when using GetInterfaceObject, the class is returned from the call allowing its methods to be called.

    Specifically, I want to rewrite this VB6 app in .NET. The app needs to pass a string of XML into my dll in AutoCAD to be processed.

    Regards,

    Brian

  10. Hi Brian,

    A couple of choices...

    To pass everything by the command-line, you can use Editor.GetString() from within your command to pick up strings that are passed in after the command-name using SendStringToExecute().

    Otherwise you can expose public methods from public classes that can be imported into other modules (a standard .NET technique for publishing libraries or modularizing your code in different assemblies).

    Regards,

    Kean

  11. Brian Stafford Avatar

    Hi Kean,

    In trying this sample, I ran into some trouble. I set references to acdbmgd, acmgd, AutoCAD 2008 Type Library, and AutoCAD/ObjectDBX Common 17.0 Type Library. The first 3 references I can do fine, but in setting the last reference, Visual Studio comes back to the references tab with 'The system cannot find the reference specified'. I am using Visual Basic 2008, AutoCAD Mechanical 2008 SP2, and Vista. Any ideas why this is happening?

    Regards,

    Brian

  12. Hi Brian,

    Sorry - I have no idea what the problem is. Re-installing is likely to help, if nothing else.

    Regards,

    Kean

  13. Brian Stafford Avatar

    Hi Kean,

    Oh well, I was hoping you would have some insight!

    Back to your first reply on "exposing public methods from public classes". Are you saying exposing them from the NETLOAD'ed dll? If so, I always get an "unable to find entry point" exception in my .exe.

    Just to clarify, I will have an out-of-process .exe written in VB.net, the NETLOAD'ed dll written in VB.net, and I need a way to call the methods in the dll.

    Any advice you can provide, or pointers to other blog entries, is greatly appreciated.

    Thanks,

    Brian

  14. Hi Brian,

    Oh, you want to call into the DLL from an EXE? In that case you really should use the command-line, whether using Editor.GetString() (etc.) or using the LispFunction attribute to also expose your commands via LISP functions.

    Either approach can then be called by SendCommand() (you should really use COM for this, as AutoCAD's .NET interface is not supported across process boundaries).

    Regards,

    Kean

  15. The above works on web applications when the vs development server is used. There is a System.Runtime.InteropServices.COMException (0x80080005) error ehen the IIS server is used.

    How do i launch AutoCad as a web application or using IIS.

  16. he above works on web applications when the vs development server is used. There is a System.Runtime.InteropServices.COMException (0x80080005) error ehen the IIS server is used.

    How do i launch AutoCad as a web application or using IIS.

    1. Have you found solution of your problem. Because i have facing same problem.

  17. Sorry, essa - I haven't any information to help you on this (it also sounds like a configuration that I doubt is supported by Autodesk).

    Kean

  18. Just curious with regards to the code section starting a new instance of AutoCAD:

    Type acType = Type.GetTypeFromProgID(progID);
    acApp = AcadApplication)Activator.CreateInstance(acType,true);

    I've noticed in using this that every now and then I get the following error:

    HRESULT: 0x80080005 (CO_E_SERVER_EXEC_FAILURE)

    What's the cause of this? If it's the result of the AutoCAD startup process, is there a way within your code sample to better handle this? BTW, I've seen this when launching AutoCAD 2012.

  19. It's likely you need to implement the approach shown in this post:

    keanw.com/2010/02/handling-com-calls-rejected-by-autocad-from-an-external-net-application.html

    At least that's my first guess...

    Kean

  20. I had seen that and implemented it already. Before I did, I was getting that message too. The message with this one is RPC_E_CALL_REJECTED versus this one being CO_E_SERVER_EXEC_FAILURE. As with the former, it too is intermittent. I can post something with ADN, but was thinking that if you've heard of this before then maybe an update to this blog could help others as well. Maybe a 2012 issue?

  21. This is a new one for me, so I suggest checking in with ADN.

    Kean

  22. Hi Kean,

    Quick question. I only have AutoCAD 2012 installed on the computer that I created the app on. It connects to AutoCAD and works as expected. If I then take the executable and run it on a computer that only has AutoCAD 2010 installed it can't connect. Is this the behavior you would expect? I also went the other direction, created the app on the computer with 2010 and it connects as expected but won't connect on the computer with only 2012 installed.

    Thanks
    Chris

  23. Hi Chris,

    Try using a version-less ProgId ("AutoCAD.Application") to see if that helps. You may also want to use type embedding (which should be an option if you're using a newer version of Visual Studio), to reduce the dependence on the version-specific typelib.

    Beyond that, ADN or someone on the discussion groups may have more pointed advice.

    I hope this helps,

    Kean

  24. This is all very interesting. I am trying to find out information on how to convert some VBA code to VB.NET. I use the VBA code to launch AutoCAD, load a LISP program and execute it. This works fine but try as I might I cannot find an equivalent using VB.NET.

  25. Kean Walmsley Avatar

    I doubt you're using VBA code to launch AutoCAD (as it only runs in-process). Could you be using VB6 code to do so? The same code should work with modest changes in VB.NET - this guide may be of help:

    keanw.com/2010/02/updated-devtv-autocad-vba-to-vbnet-migration-basics.html

    Kean

  26. If there are multiple versions and flavors of AutoCAD on the machine, how can we ensure that a specific version and flavor of acad.exe is launched? ex. AutoCAD (vanilla(, Civil3D, AutoCAD Electrical etc...

  27. Launching via COM starts the most recently run product (of that version).

    The only way I know to force this is to launch the desired version via its EXE and then the next time you launch via COM, it'll get picked up. ScriptPro 2.0 does this programmatically, for instance.

    Kean

  28. Very helpful as always! Thank you 🙂

  29. Hey Kean, is it possible to download all your examples?

  30. Hi there,

    Sorry - I don't have them compiled together in a way that could easily be shared, unfortunately.

    Regards,

    Kean

  31. Hi Kean,

    I'm trying to launch Acad2012 as per your code above.
    It starts all right, the starting program can drive it, but if I try to use it normally, the UI is somehow messed up. The first command using a dialog leads to a crash. At least it seems like the problem is the UI, as commands from the command line work.
    Any idea what might be wrong?
    BTW, launching A2008 the same way works as expected, no problems.

    Thanks,

    alex

    1. Hi alex,

      I don't recall having seen this before. I'm heading off on vacation - can you post to the discussion group?

      I also suggest making sure it's not machine-specific, if at all possible.

      Thanks,

      Kean

      1. Kean,

        It looks like something is changed in A2012 regarding the UI (UI thread blocking or something).
        Anyway; I'll post to the group.
        Maybe you could run your code with A2012 and see what happens on your machine. I tried it on two computers and it is the same.

        Enjoy your vacation,

        alex

  32. I have auto-cad 2019 installed on my machine, I am following your sample code, how do I know the prog Id of AutoCAD on my machine for example you have above const string progID = "AutoCAD.Application.17.1". I am able to launch when I set progID to "AutoCAD.Application" but it wont find an existing instance with this prog ID.

    1. You can check the Registry or ask on the AutoCAD forums.

      Kean

    2. 17=> AutoCAD 2007 (perhaps SP1... as for 17.1)
      So for AutoCAD 2019 change it to 23

      de.m.wikipedia.org/...

Leave a Reply to Brian Stafford Cancel reply

Your email address will not be published. Required fields are marked *