Kean Walmsley

July 2009

Sun Mon Tue Wed Thu Fri Sat
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31  

Twitter Updates

    follow me on Twitter



    « Custom objects in .NET | Main | Optimizing the loading of AutoCAD .NET applications »

    September 06, 2006

    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.

    TrackBack

    TrackBack URL for this entry:
    http://www.typepad.com/services/trackback/6a00d83452464869e200d834680b7069e2

    Listed below are links to weblogs that reference Initialization code in your AutoCAD .NET application:

    » Optimizing the loading of AutoCAD .NET applications from sdphg
    Optimizing the loading of AutoCAD .NET applications [Read More]

    Comments

    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.

    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

    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.

    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

    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?

    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 ;-)

    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. :-)

    Verify your Comment

    Previewing your Comment

    This is only a preview. Your comment has not yet been posted.

    Working...
    Your comment could not be posted. Error type:
    Your comment has been posted. Post another comment

    The letters and numbers you entered did not match the image. Please try again.

    As a final step before posting your comment, enter the letters and numbers you see in the image below. This prevents automated programs from posting comments.

    Having trouble reading this image? View an alternate.

    Working...

    Post a comment

    Feed & Share

    Search