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
);
}
}
// Determine 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
{
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.