October 2014

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  










« Recorded presentation on Autodesk's Component Technologies | Main | Showing AutoCAD's hatch dialog from a .NET application »

March 15, 2007

Getting the list of .NET-defined commands in AutoCAD

Here's an interesting question that came in from Kerry Brown:

Is there a way to determine the names of Commands loaded into Acad from assemblies ... either a global list or a list associated with a specific assembly ... or both :-)

I managed to put some code together to do this (although I needed to look into how AutoCAD does it to get some of the finer points). I chose to implement two types of command - one that gets the commands for all the loaded assemblies, and one that works for just the currently-executing assembly. The first one is quite slow, though - it takes time to query every loaded assembly - so I added a command that only queries assemblies with explicit CommandClass attributes.

I didn't write a command to get the commands defined by a specified assembly - that's been left as an exercise for the reader. :-)

Here is the C# code:

using Autodesk.AutoCAD.ApplicationServices;

using Autodesk.AutoCAD.EditorInput;

using Autodesk.AutoCAD.Runtime;

using System;

using System.Reflection;

using System.Collections.Specialized;


namespace GetLoadedCommands

{

  public class Commands

  {

    [CommandMethod("TC")]

    static public void ListCommandsFromThisAssembly()

    {

      // Just get the commands for this assembly


      DocumentCollection dm =

        Application.DocumentManager;

      Editor ed =

        dm.MdiActiveDocument.Editor;


      Assembly asm =

        Assembly.GetExecutingAssembly();

      string[] cmds = GetCommands(asm, false);

      foreach (string cmd in cmds)

      {

        ed.WriteMessage(cmd + "\n");

      }

    }


    [CommandMethod("LCM")]

    static public void ListMarkedCommands()

    {

      // Get the commands for all assemblies,

      //  but only those with explicit

      // CommandClass attributes (much quicker)


      StringCollection cmds = new StringCollection();

      DocumentCollection dm =

        Application.DocumentManager;

      Editor ed =

        dm.MdiActiveDocument.Editor;


      Assembly[] asms =

        AppDomain.CurrentDomain.GetAssemblies();

      foreach (Assembly asm in asms)

      {

        cmds.AddRange(GetCommands(asm, true));

      }

      foreach (string cmd in cmds)

      {

        ed.WriteMessage(cmd + "\n");

      }

    }


    [CommandMethod("LC")]

    static public void ListCommands()

    {

      // Get the commands for all assemblies,

      // marked or otherwise (much slower)


      StringCollection cmds = new StringCollection();

      DocumentCollection dm =

        Application.DocumentManager;

      Editor ed =

        dm.MdiActiveDocument.Editor;


      Assembly[] asms =

        AppDomain.CurrentDomain.GetAssemblies();

      foreach (Assembly asm in asms)

      {

        cmds.AddRange(GetCommands(asm, false));

      }

      foreach (string cmd in cmds)

      {

        ed.WriteMessage(cmd + "\n");

      }

    }


    private static string[] GetCommands(

      Assembly asm,

      bool markedOnly

    )

    {

      StringCollection sc = new StringCollection();

      object[] objs =

        asm.GetCustomAttributes(

          typeof(CommandClassAttribute),

          true

        );

      Type[] tps;

      int numTypes = objs.Length;

      if (numTypes > 0)

      {

        tps = new Type[numTypes];

        for(int i=0; i < numTypes; i++)

        {

          CommandClassAttribute cca =

            objs[i] as CommandClassAttribute;

          if (cca != null)

          {

            tps[i] = cca.Type;

          }

        }

      }

      else

      {

        // If we're only looking for specifically

        // marked CommandClasses, then use an

        // empty list

        if (markedOnly)

          tps = new Type[0];

        else

          tps = asm.GetExportedTypes();

      }


      foreach (Type tp in tps)

      {

        MethodInfo[] meths = tp.GetMethods();

        foreach (MethodInfo meth in meths)

        {

          objs =

            meth.GetCustomAttributes(

              typeof(CommandMethodAttribute),

              true

            );

          foreach (object obj in objs)

          {

            CommandMethodAttribute attb =

              (CommandMethodAttribute)obj;

            sc.Add(attb.GlobalName);

          }

        }

      }

      string[] ret = new string[sc.Count];

      sc.CopyTo(ret,0);

      return ret;

    }

  }

}

And here's what happens when you run the various commands:

Command: TC

TC

LCM

LC


Command: LC

layer

TC

LCM

LC


Command: LCM

layer

Note: you'll see that our own module's command are not listed by LCM... if you add the CommandClass attribute, as mentioned in this earlier post, then they will be:

[assembly:

  CommandClass(

    typeof(GetLoadedCommands.Commands)

  )

]

TrackBack

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

Listed below are links to weblogs that reference Getting the list of .NET-defined commands in AutoCAD:

blog comments powered by Disqus

Feed/Share

10 Random Posts