Initialization code in your AutoCAD .NET application

It's very common to need to execute some code as your application modules are loaded, and then to clean-up as they get unloaded or as AutoCAD terminates. Managed AutoCAD applications can do this by implementing the Autodesk.AutoCAD.Runtime.IExtensionApplication interface, which require Initialize() and Terminate() methods.

During the Initialize() method, you will typically want to set system variables and perhaps call commands which execute some pre-existing initialization code for your application.

Here's some code showing how to implement this interface using VB.NET:

Imports Autodesk.AutoCAD.Runtime

Imports Autodesk.AutoCAD.ApplicationServices

Imports Autodesk.AutoCAD.EditorInput

Imports System

Public Class InitializationTest

  Implements Autodesk.AutoCAD.Runtime.IExtensionApplication

  Public Sub Initialize() Implements _

  IExtensionApplication.Initialize

    Dim ed As Editor = _

      Application.DocumentManager.MdiActiveDocument.Editor

    ed.WriteMessage("Initializing - do something useful.")

  End Sub

  Public Sub Terminate() Implements _

  IExtensionApplication.Terminate

    Console.WriteLine("Cleaning up...")

  End Sub

  <CommandMethod("TST")> _

  Public Sub Test()

    Dim ed As Editor = _

      Application.DocumentManager.MdiActiveDocument.Editor

    ed.WriteMessage("This is the TST command.")

  End Sub

End Class

And here's the equivalent code in C#:

using Autodesk.AutoCAD.Runtime;

using Autodesk.AutoCAD.ApplicationServices;

using Autodesk.AutoCAD.EditorInput;

using System;

public class InitializationTest

  : Autodesk.AutoCAD.Runtime.IExtensionApplication

{

  public void Initialize()

  {

    Editor ed =

      Application.DocumentManager.MdiActiveDocument.Editor;

    ed.WriteMessage("Initializing - do something useful.");

  }

  public void Terminate()

  {

    Console.WriteLine("Cleaning up...");

  }

  [CommandMethod("TST")]

  public void Test()

  {

    Editor ed =

      Application.DocumentManager.MdiActiveDocument.Editor;

    ed.WriteMessage("This is the TST command.");

  }

}

A few notes about this code:

.NET modules are not currently unloaded until AutoCAD terminates. While this is a popular request from developers (as it would make debugging much simpler), my understanding is that this is an issue that is inherent to the implementation of .NET - see this MSDN blog post for more information.

What this means is that by the time the Terminate() method is called, AutoCAD is already in the process of closing. This is why I've used Console.Write() rather than ed.WriteMessage(), as by this point there's no command-line to write to.

That said, you can and should use the Terminate() callback to close any open files, database connections etc.

Something else you might come across when implementing this... I've implemented a single command in this application for a couple of reasons: in my next post I'm going to segregate the command into a different class, to show how you can tweak your application architecture both to follow a more logical structure and to optimize load performance.

The second reason I added the command was to raise a subtle you might well hit while coding: you might see the initialization string sent to the command-line as the application loads, but then the command is not found when you enter "TST" at the command-line. If you experience this behaviour, you're probably hitting an issue that can come up when coding managed applications against AutoCAD 2007: there's been a change in this version so that acmgd.dll is loaded on startup, and under certain circumstances this assembly might end up getting loaded again if found on a different path, causing your commands not to work.

The issue can be tricky to identify but is one that can be resolved in a number of ways:

  1. Edit the Registry to disable the demand-loading "load on startup" of acmgd.dll (a bad idea, in my opinion - it's safer not to second guess what assumptions might have been made about the availability of core modules)
  2. Make sure AutoCAD is launched from its own working directory - commonly this issue is hit while debugging because Visual Studio doesn't automatically pick up the debugging application's working directory
  3. Set the "Copy Local" flag for acmgd.dll to "False". "Copy Local" tells Visual Studio whether the build process should make copies of the assemblies referenced by the project in its output folder

My preference is for the third approach, as on a number of occasions I've overwritten acmgd.dll and acdbmgd.dll with those from another AutoCAD version (inadvertently trashing my AutoCAD installation). This usually happens when testing projects across versions (projects that's I've set to output directly to AutoCAD's program folder, for convenience), and I've forgotten to change the assemblies references before building.

So I would actually set both your references to acdbmgd.dll and acmgd.dll to "Copy Local = False". You can do this either by selecting the Reference(s) via the Solution Explorer (in C#) or via the References tab in your Project Properties (in VB.NET) and then editing the reference's Properties.

15 responses to “Initialization code in your AutoCAD .NET application”

  1. Hi Kean,
    First of all, I would like to thank you for having such a fantastic source of information on the AutoCAD .NET API. I found it to be the best resource to get started with AutoCAD .NET programming.

    My question is the following: my app needs to create a toolbar. I want the toolbar to load on startup, so I created it at my IExtensionApplication implementation class. I can see the toolbar when AutoCAD starts up, but once the Initialize() method is executed, the toolbar hides again. So I am wandering if this is the right place to create the toolbar.

    Thanks in advance 🙂

    Rubén D.M.

  2. Hi Rubén,

    Thanks for your feedback - very nice of you.

    I'd suggest posting some code reproducing the problem to the AutoCAD .NET discussion group and sending me the URL by email (otherwise, if you're an ADN member, submit the project via DevHelp Online and email me the case ID).

    Regards,

    Kean

  3. Alberto Benitez Avatar
    Alberto Benitez

    Hello,

    I create a VB.NET program that call autocad 2004
    network version, and I run a lisp rutine.
    few days ago I install Autocad 2007, now if I have open 2007, run a new sesion for autocad 2007, but I just want my Vb.Net program that work
    with 2004 network version.

    if any way to call a specific version of autocad from VB.NET.

    Thank you.

  4. Hi Alberto,

    Unfortunately it's not clear to me what exactly you need help with, and neither does it appear related to this post...

    Please submit a more detailed description either to one of the discussion groups, or to the ADN team, if you're a member.

    Regards,

    Kean

  5. Hi Kean,

    I'm wondering what state the document (and/or application) is in when the initialize method fires. My first guess would be that it is locked/busy, and therefore any code which attempted to read from the Database would fail due to the document being locked?

  6. I'm amazed... All the other things I ever tried, like calling a SetVars routine from the MNL file or the ACADDOC.lsp, would always fail saying there was a lock violation when I tried to read an Extension Dictionary on AutoCAD startup, or on DocumentActivated. I netload my dll from an MNL file so this initialize method executed even before the ACADDOC.lsp, but it works this way...no lock violation.

    BTW, I don't think I'm going to be able to make AU 2008, but if you ever find yourself in the Denver, CO area with some time to kill, I definitely owe you a beer. Actually a person could die from alcohol poisoning if you drank all the beers I owe you in one sitting 😉

  7. A great question. You actually can't rely on the document being ready for you to do anything much at all - if your module is set up to load on AutoCAD initialization, there's no guarantee you even have an active document.

    What I tend to do is to P/Invoke ads_queueexpr() to fire off a command with my initialization stuff:

    [assembly: ExtensionApplication(typeof(MyNamespace.Application))]

    namespace MyNamespace
    {
    class Application : IExtensionApplication
    {
    [DllImport("acad.exe", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
    extern static private int ads_queueexpr(string strExpr);

    public void Initialize()
    {
    ads_queueexpr("(command \"_INITMYAPP\")");
    }

    ...

    This seems worthy of a follow up post (one for the list).

    Kean

    P.S. Sounds like a great offer... haven't been to the mile-high city in many moons, but then you never know. 🙂

  8. The version above (using ads_queueexpr() during Initialize()) seems not to work on Autocad 2010 SP1 when the command is in the same assembly but in a different CommandClass. During Initialize() the other class is not created yet.
    It worked for me to call the command inside the constructor of the CommandClass

    [assembly: CommandClass( typeof( Class1 ) )]

    public class Class1
    {
    public Class1()
    {
    Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
    ed.WriteMessage( "Class1 created" );
    ShowDialog( );
    }

    [CommandMethod( "ShowDialog" )]
    public void ShowDialog( )
    {
    ...
    }

    May this helps some people.

    Armin

  9. Calling the command function directly from the class constructor is a little risky, in my opnion: you have no guarantees AutoCAD is in a position to execute your command at that point (your app could have been demand-loaded on AutoCAD startup, for instance). Plus it bypasses the automatic document-locking, so the behaviour will need to be coded differently.

    I don't believe I've tried ads_queueexpr() on 2010 SP1 specifically, but I'm surprised there's an issue with commands in the same assembly but different comamnd-class. The commands are basically queued up via the command input mechanism and should not be executed immediately.

    Kean

  10. Hi Kean,

    When I am Calling the AutoACd test function from my website i am getting the errror

    Common Language Runtime detected an invalid program.

    Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

    Exception Details: System.InvalidProgramException: Common Language Runtime detected an invalid program.

    Source Error:

    Line 13:
    Line 14: InitializationTest b = new InitializationTest();
    Line 15: b.Test();
    Line 16: Class1 a = new Class1();
    Line 17:

    test function is =============================

    using System;

    using System.Collections.Generic;

    using System.Linq;

    using System.Text;

    using System.Threading.Tasks;

    using Autodesk.AutoCAD.Runtime;

    using Autodesk.AutoCAD.ApplicationServices;

    using Autodesk.AutoCAD.EditorInput;

    namespace ClassLibrary2

    {

    public class InitializationTest

    : Autodesk.AutoCAD.Runtime.IExtensionApplication

    {

    public void Initialize()

    {

    Editor ed =

    Application.DocumentManager.MdiActiveDocument.Editor;

    ed.WriteMessage("Initializing - do something useful.");

    }

    public void Terminate()

    {

    Console.WriteLine("Cleaning up...");

    }

    [CommandMethod("TST")]

    public void Test()

    {

    Editor ed =

    Application.DocumentManager.MdiActiveDocument.Editor;

    ed.WriteMessage("This is the TST command.");

    }

    }

    }

    1. When you say you're calling this from your website, does this mean your website is trying to launch and call into AutoCAD? If so, this is definitely not the way to go about it.

      Kean

      1. What should i have to do?

  11. Hello Sir,

    Thank you for these valuable resources. I am new with programming. I am trying to create my first plugin for AutoCAD but having some issues.

    In the line "[assembly: CommandClass(typeof(MoldPlast.Class1))]" I am having an error The type or namespace name 'CommandClass' cound not be found and same type of errors with below lines :-

    1. [CommandMethod("AdskGreeting")]

    2. Document acDoc = Application.DocumentManager.MdiActiveDocument;

    I will be very grateful of you. Kindly guide me what should I do

    1. Hello Vishal,

      This is not a support forum. Please post your questions here:

      forums.autodesk.com/

      Regards,

      Kean

      1. @keanw:disqus : Thank You Sir !

Leave a Reply

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