Iterating AutoCAD system variables using .NET – Part 1

On my flight across to Toronto, I took another look at the "What's New in AutoCAD 2015" section of the .NET API documentation and decided to dig into the new SystemVariableEnumerator implementation.

I was particularly curious about this feature as there is already a way to get access to system variables via the Autodesk.AutoCAD.Runtime.SystemObjects.Variables collection. As an initial look at these two classes, I decided to put together a couple of simple variable iterator commands that use the same function to print out some information concerning the system variables exposed by each collection.

Here's the C# code implementing two commands, ESV and ESV2, which use the two mechanisms for getting the list of AutoCAD system variables:

using Autodesk.AutoCAD.ApplicationServices;

using Autodesk.AutoCAD.ApplicationServices.Core;

using Autodesk.AutoCAD.EditorInput;

using Autodesk.AutoCAD.Geometry;

using Autodesk.AutoCAD.Runtime;

using System;

 

namespace SystemVariableEnumeration

{

  public class Commands

  {

    [CommandMethod("ESV")]

    public static void EnumerateSysVars()

    {

      var doc = Application.DocumentManager.MdiActiveDocument;

      if (doc == null)

        return;

      var ed = doc.Editor;

 

      // Use the existing SystemObjects iteration mechanism

 

      foreach (var v in SystemObjects.Variables)

      {

        PrintVariable(ed, v);

      }

    }

 

    [CommandMethod("ESV2")]

    public static void EnumerateSysVars2()

    {

      var doc = Application.DocumentManager.MdiActiveDocument;

      if (doc == null)

        return;

      var ed = doc.Editor;

 

      // Use the new system variable enumerator

 

      var sve = new SystemVariableEnumerator();

 

      while (sve.MoveNext())

      {

        var v = sve.Current;

        if (v != null)

        {

          PrintVariable(ed, v);

        }

      }

    }

 

    // Helper function to print out the information about

    // a particular variable

 

    private static void PrintVariable(Editor ed, Variable v)

    {

      var t = GetType(v.PrimaryType);

 

      ed.WriteMessage(

        "\n{0} ({1}, {2} - {3}): {4}",

        v.Name,

        t == null ? "null" : t.Name,

        v.PrimaryType, v.SecondaryType, v.TypeFlags

      );

 

      if (v.Range != null)

      {

        ed.WriteMessage(

          " [{0}...{1}]",

          v.Range.LowerBound, v.Range.UpperBound

        );

      }

    }

 

    // Dete
rmine the type of a system variable based on

    // the internal representation

 

    private static System.Type GetType(short v)

    {

      Type ret = null;

 

      switch (v)

      {

        case 1:

        case 5001: // RTREAL real number

          {

            ret = typeof(Double);

            break;

          }

        case 2:

        case 5002: // RTPOINT: 2D point X and Y only

          {

            ret = typeof(Point2d);

            break;

          }

        case 3:

        case 5003: // RTSHORT: short integer

          {

            ret = typeof(Int16);

            break;

          }

        case 4:

        case 5004: // RTANG: angle

          {

            ret = null; // Angle

            break;

          }

        case 5:

        case 5005: // RTSTR: string

          {

            ret = typeof(String);

            break;

          }

        case 6:

        case 5006: // RTENAME: entity name

          {

            ret = null;

            break;

          }

        case 7:

        case 5007: // RTPICKS: pick set

          {

            ret = null;

            break;

          }

        case 8:

        case 5008: // RTORIENT: orientation

          {

            ret = null; // Orientation

            break;

          }

        case 9:

        case 5009: // RT3DPOINT: 3D point - X, Y and Z

          {

            ret = typeof(Point3d);

            break;

          }

        case 10:

        case 5010: // RTLONG: long integer

     &
#160;    {

            ret = typeof(Int32);

            break;

          }

        case 11:

        case 5011: // 2D extents of some kind

          {

            ret = typeof(Point2d);

            break;

          }

      }

      return ret;

    }

  }

}

We won't look at the output to the command-line in this post, as there's a lot there. Hopefully the format of the data printed to the command-line is obvious from the code.

A big chunk of this code actually "decodes" the type information, returning a System.Type object when it can make sense of the number passed in (which may be a 50xx number or a shorter enumeration, depending on which mechanism has been used).

It's also worth noting that it wasn't quite as simple as doing a "foreach" on the new API: it seems there's a GetEnumerator() method missing which means we can't simplify our code in that way, unfortunately (hence the long-hand approach using MoveNext() etc.). Hopefully someone will tell me I've made a mistake somewhere in my code and that it is, in fact, possible. ๐Ÿ™‚

The newer enumerator skips over "hidden" system variables โ€“ those with an asterisk ("*") prefix on their name โ€“ which do get returned as part of the SystemObjects collection.

The SystemObjects collection does allow you to set the value of a variable, which is pretty interesting. In a future post we'll take a look at this capability as well as comparing the performance of the two mechanisms, to see which is most efficient.

7 responses to “Iterating AutoCAD system variables using .NET – Part 1”

  1. Hi Kean,

    Problem is SystemVariableEnumerator is just the enumerator and not the enumerable. Only way I could see was to create an additional wrapper class:

    public class SystemVariableWrapper : IEnumerable
    {
    public IEnumerator GetEnumerator()
    {
    return new SystemVariableEnumerator();
    }
    }

    Then you can:

    var sve = new SystemVariableWrapper();
    foreach (Variable v in sve)
    PrintVariable(ed, v);

    Toss-up whether the overhead of the wrapper class is worth it

    Cheers
    Jon

    1. Kean Walmsley Avatar

      Hi Jon,

      That's what I'd thought: thanks for confirming!

      Cheers,

      Kean

  2. Hi Kean
    With SystemObjects.Variables, I miss many Variables like "Pickbox", "Filedia" and so on. Is there a method to get all AutoCAD Variables, also some in dwg saved?

    1. Kean Walmsley Avatar

      Hi Ralf,

      What release are you using? I think more and more sysvars are being added, over time, but there could well still be some gaps. You might also contact ADN or post to the discussion groups on this... someone there may have information to share.

      Regards,

      Kean

      1. Hi Kean,
        Normaly I develop with AutoCAD 2013 but i tried also with 2016. I get much more variables but still miss many.. For me it seems that there is a difference between systemvariables and uservariables. Am I wrong?
        Regards, Ralf

        1. Kean Walmsley Avatar

          Hi Ralf,

          If there are gaps, they should be reported via ADN or the discussion group. The docs say:

          "This class provides a way to iterator over all of the public system variables and get their names, data type, range (if applicable), read-only status, and how they are stored.

          System variables that have their secret flag set or that have a "*" as the first character in their name are skipped by this iterator."

          So either we need to adjust the documentation or complete the coverage.

          (Please don't submit them here - I'm not in a position to provide help with addressing this.)

          Regards,

          Kean

          1. Gnarly Gorilla Avatar
            Gnarly Gorilla

            Has anyone done what Kean suggested to Ralf; on a forum someplace? If so, can you please post link?

Leave a Reply to Kean Walmsley Cancel reply

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