Launching AutoCAD with a specific profile using .NET

This is a follow-up to this previous post, where we used COM to launch the AutoCAD process. Tony Tanzillo rightly pointed out the code in that post could be simplified slightly, so check out his comment for the specifics.

Today we're going to look at launching AutoCAD more manually, allowing us to control the working folder and specify command-line parameters. This is to address the specific question of choosing an alternative startup profile for the application, but AutoCAD's command-line parameters allow you to do a great deal more than that.

We're going to use the System.Diagnostics namespace to specify our options and launch our process, and then use COM to connect to it (so we can use the COM Automation API, as before, to run commands, etc.).

Here are the namespace declarations:

using System;

using System.Diagnostics;

using System.Runtime.InteropServices;

using Autodesk.AutoCAD.Interop;

And here's the C# code to implement your function or button message-handler:

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

  // The @ means it's a literal string - no need

  // for double backslashes

  const string exePath =

    @"c:\Program Files\Autodesk\AutoCAD 2008\acad.exe";

  AcadApplication acApp = null;

  // Let's first check we don't have AutoCAD already running

  try

  {

    acApp =

      (AcadApplication)Marshal.GetActiveObject(progID);

  }

  catch {}

  if (acApp != null)

  {

    MessageBox.Show(

      "An instance of AutoCAD is already running."

    );

  }

  else

  {

    try

    {

      // Use classes from the System.Diagnostics namespace

      // to launch our AutoCAD process with command-line

      // options

      ProcessStartInfo psi =

        new ProcessStartInfo(exePath, "/p myprofile");

      psi.WorkingDirectory = @"c:\temp";

      Process pr = Process.Start(psi);

      // Wait for AutoCAD to be ready for input

      // This doesn't wait until AutoCAD is ready

      // to receive COM requests, it seems

      pr.WaitForInputIdle();

      // Connect to our process using COM

      // We're going to loop infinitely until we get the

      // AutoCAD object.         

      // A little risky, unless we implement a timeout

      // mechanism or let the user cancel

      while (acApp == null)

      {

        try

        {

          acApp =

            (AcadApplication)Marshal.GetActiveObject(progID);

        }

        catch

        {

          // Let's let the application check its message

          // loop, in case the user has exited or cancelled

          Application.DoEvents();

        }

      }

    }

    catch (Exception ex)

    {

      MessageBox.Show(

        "Cannot create or attach to AutoCAD object: "

        + ex.Message

      );

    }

  }

  if (acApp != null)

  {

    acApp.Visible = true;

    acApp.ActiveDocument.SendCommand("_MYCOMMAND ");

  }

Well, that's it for 2007. A Happy Holidays to you all, and a Merry Christmas & Happy New Year to those of you who celebrate these events.

See you in 2008!

16 responses to “Launching AutoCAD with a specific profile using .NET”

  1. Hi Kaen,

    The article is extremely useful and thanks for the same.

    However, I wanted to find out if the process is ready to receive COM inputs?

    As you have mentioned here ..."This doesn't wait until AutoCAD is ready to receive COM requests, it seems"!! Can I find out the busy state of AutoCAD?

    Regards,
    Manoj

  2. Hi Manoj,

    That's why we're looping until we get the COM object: if AutoCAD was ready to answer a question about whether it was busy or not, by definition it would no longer be busy! 🙂

    Kean

  3. Senthilkumar Avatar

    Hi Kean,

    Thanks for this post.
    Is it possible to launch AutoCAD in two different sessions?
    Actually I tried to create another instance of AutoCAD, but it is throwing error as Another AutoCAD session is running. My requirement is that another AutoCAD session need to be opened without disturbing previous one. Can I open another AutoCAD session without closing previous session?

  4. Kean Walmsley Avatar
    Kean Walmsley

    You can usually launch up to two sessions of AutoCAD. The problem you'll have is connecting to the second one: GetActiveObject() is likely to always return the first in the ROT (Running Object Table).

    It can probably be worked around, but it won't be straightforward.

    Kean

  5. Senthilkumar Avatar

    Thanks for you reply. I am able to launch the AutoCAD application and setting the AutoCAD window as child window in my application. I want to disable the close button ( X ) in the AutoCAD window. Is it possible to disable? if yes, can you please provide the details?

  6. Kean Walmsley Avatar

    You can simply UNDEFINE QUIT.

    Regards,

    Kean

  7. Hi Kean,

    First, thanks for your site it has been the best resource for AutoCAD .net out there. Keep up the good work.

    I am using this method to connect/open AutoCAD from an application and load a .net dll i.e. "netload" to do, as you put it, "the heavy lifting".
    I am doing this by sending a lisp function to the command line i.e.

    acApp.ActiveDocument.SendCommand("(defun c:LoadMyAPP() (Command ""_netload"" ""C:\\MyApp.dll"")(princ)) ")
    acApp.ActiveDocument.SendCommand("LoadMyAPP ")
    (Sorry it’s in very basic for those scratching the heads with the double quotes...)

    Is there a way you can load a .net dll from the com library like the ‘loadapp’ functions in arx, or using Autodesk.AutoCAD.Runtime.ExtensionLoader given that we are out of process?
    I am assuming you can't use the AutoCad.Runtime out of process. Is this correct?

    What I am trying to achieve is load my application on demand ie load menus and custom application when a user clicks on a short cut on the desktop, is there an easier way to do this?

    Regards from Down Under,
    Evan

  8. Hi Evan,

    The best way is to load your module when a particular command is called. As you're out of proces, the cleanest is to use COM's SendCommand() to launch a dummy command that need do nothing but cause the module to be loaded (it probably makes sense for there to be at least an empty command called, though, to avoid an "unknown command" message).

    I hope this helps,

    Kean

  9. Great site bro.

    "GetActiveObject() is likely to always return the first in the ROT"

    I realize this is not an AutoCAD specific problem and I'm looking for solutions elsewhere but if anyone found a way around this I'd be keen to hear it.

  10. Kean Walmsley Avatar

    If working inside AutoCAD, there's a tool called AdskUnsupp that exposes some tricky things to do in C++ via COM. This allows you to get - and choose between - the various running instances of AutoCAD-based products.

    I suggest asking over on the ADN DevBlog or the AutoCAD .NET Discussion Group.

    Kean

  11. Cheers. The "Tricky" part scared be off - I'm just a jungle-coder.

    As a cheap-and-nasty alternative I tried including a dummy file in the PSI so that I could Marshal.BindToMoniker(lewinskyFile), good enough to get a link then close the dummy file. Unfortunately it linked as a generic system.___com object and I wasted 4 hours of Sunday trying to convince my app to cast it to native.

    In the end I've gone with plan 'C', the guts of which is:
    ...
    if (!string.IsNullOrEmpty(profile))
    {
    //fiddle the registry so default profile is our wanted...
    ModifyRegistry modReg = new ModifyRegistry();
    modReg.BaseRegistryKey = Microsoft.Win32.Registry.CurrentUser;
    modReg.SubKey = @"Software\Autodesk\AutoCAD\R17.1\ACAD-6001:409\Profiles";
    modReg.Write(string.Empty, profile);
    }
    acadApp = new AcadApplication();
    ...

    Good enough, I'm out of time!

    1. Mohamed Ahmed Avatar

      hi Kean I know its old post but I have tow questions
      1- What is psi.WorkingDirectory = @"c:\temp";
      What I used In this directory

      2- how can I set profile current ?
      thnx

  12. Mohamed Ahmed Avatar

    hi Kean I know its old post but I have tow questions
    1- What is psi.WorkingDirectory = @"c:\temp";
    What I used In this directory

    2- how can I set profile current ?

    thnx a lot

    1. Kean Walmsley Avatar

      It is old and I'm on an extended trip with my family. Please post to the discussion groups if you need assistance.

      Kean

  13. Hi Kean,
    All the similar blogs Launching AutoCAD refer to a certain AutoCAD-Version.
    Is it possible to choose and launch different AutoCAD-Versions at runtime and get their acApp?

    Binding the project with a certain AutoCAD type library (lets say SDK 2021) ->
    "acApp =(AcadApplication)Marshal.GetActiveObject(progID)" is NULL for all versions other than 2021!

    void lauchAutoCADdoSomething(int nVer) {

    AcadApplication acApp = null;
    string progID;

    if (nVer == 2007) {
    progID = "AutoCAD.Application.17.1";
    }
    .....
    .....
    if (nVer == 2020) {
    progID = "AutoCAD.Application.23.1";
    }
    if (nVer == 2021) {
    progID = "AutoCAD.Application.24";
    }

    acApp =(AcadApplication)Marshal.GetActiveObject(progID);

    if (acApp != null)
    {

    acApp.Visible = true;
    AcadDocuments acDocs = acApp.Documents;
    ......
    .....
    acApp.ActiveDocument.SendCommand("_MYCOMMAND ");
    .....
    .....

    }

    return;
    }

    1. Hi Patric,

      Unfortunately I'm no longer working with AutoCAD (and also don't provide support). Please post your support questions to the relevant Autodesk forum.

      Thank you,

      Kean

Leave a Reply to Patric Cancel reply

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