2006年9月6日

Initialization code in your AutoCAD .NET application

Initialization code in your AutoCAD .NET application

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.

留下您的评论