Getting the names of the colors in an AutoCAD color-book using .NET

The last post got me thinking about how to get the names of all the colours that are contained in a particular color-book inside AutoCAD (the last post also contains the explanation for my using both "color" and "colour" in the same sentence, in case that bothers anyone :-).

Color-books are stored in .acb files: these files are essentially XML files with the RGB values encoded to prevent people from editing them and polluting the colour definitions on a particular system. So while the RGB information is not directly useful, it is very possible to iterate through these files and extract the names of the colours contained in a particular color-book.

This was also an excuse for me to look at the XmlReader class, to see how I might use that. It turns out that you can't instanciate an XmlReader directly - it's an abstract class. You need to use one of its concrete children, such as XmlTextReader or XmlNodeReader. XmlNodeReader gives you tree-like access to the XML content (such as you get when using the DOM to read an XML file), while the XmlTextReader is a forward-only reader which allows you to (for all intents and purposes) stream in XML content such as you might when using SAX. To understand how XmlTextReader differs from SAX, see this brief comparison.

I have historically used DOM to read XML files that need to maintained in their entirety (as they have internal references, etc.) and SAX when this was less of a concern (such as when iterating through to harvest certain data). SAX was always quicker, but you had to maintain more state information if the content was inter-related.

In this case I would therefore have chosen SAX over DOM, so in the .NET world this means XmlTextReader is the class to use.

One other quick comment on the implementation: the code uses HostApplicationServices.FindFile() to find the location of the particular .acb file we're interested in (typically inside "Support/Color" beneath the AutoCAD install folder).

Here's the C# code:

using Autodesk.AutoCAD.Runtime;

using Autodesk.AutoCAD.ApplicationServices;

using Autodesk.AutoCAD.DatabaseServices;

using Autodesk.AutoCAD.EditorInput;

using System;

using System.Xml;

namespace ColorBookApplication

{

  public class Commands

  {

    [CommandMethod("LC")]

    static public void ListRalColors()

    {

      Document doc =

        Application.DocumentManager.MdiActiveDocument;

      Database db = doc.Database;

      Editor ed = doc.Editor;

      string loc =

        HostApplicationServices.Current.FindFile(

          "ral classic.acb",

          db,

          FindFileHint.Default

        );

      XmlTextReader xr =

        new XmlTextReader(loc);

      while (xr.Read())

      {

        xr.MoveToContent();

        if (xr.NodeType == XmlNodeType.Element &&

            xr.LocalName == "colorName")

        {

          if (xr.Read())

          {

            if (xr.HasValue)

            {

              ed.WriteMessage("\n" + xr.Value);

            }

          }

        }

      }

      xr.Close();

    }

  }

}

And here's what happens when we run the LC command:

Command: lc

RAL 1000

RAL 1001

RAL 1002

... entries deleted...

RAL 9016

RAL 9017

RAL 9018

10 responses to “Getting the names of the colors in an AutoCAD color-book using .NET”

  1. Kean,
    I know this is off topic, but would you be able to show how to display a modal userform to open two drawings and add an entity on each one, any entity. Thanks

  2. Nice one Kean.

  3. HJohn,

    Do you mean modal or modeless? Modal forms are launched by commands and control of the UI: opening documents (or even switching between documents) is not going to work from a classic modal dialog.

    Regards,

    Kean

  4. Kean,
    Thanks for replaying. I meant modal, I think for modeless dialogs there is no problems. I thought there must be a way of switching the execution context from application to document and vice verse; perhaps it would be necessary to lock the documents. I have tried multi thread app, just to see how they work, I know that a thread can access another thread thru a delegate. I don't know much and don't have the right documentation, but an experienced programmer could find the solution much easier. May be what I am trying to do, it just not possible at all and the use of modal dialogs in AutoCAD .NET to modify different dwg files is not permitted.

  5. Actually, thinking about it... have you tried registering the command that launches the dialog as a "session context" command?

    I'm not fully sure that this is workable (given the fact a dialog will remain open), but it's worth a shot.

    Kean

  6. Absolutely, here is my command declaration:
    <commandmethod("addrev", commandflags.session)=""> _
    Public Shared Sub RevisionBox()
    Dim frm As New frmRevision
    Autodesk.AutoCAD.ApplicationServices.Application.ShowModelessDialog(frm)
    End Sub
    I would like to think that there must be a way of doing this, it is just outside my level. In VBA, it works fine. If the dialog and the command are in the app context, I don’t understand why it won't be possible to open a document?

  7. I guess the CommandMethod was removed, but here it is: CommandMethod("ADDREV", CommandFlags.Session)

  8. VBA has different plumbing than ObjectARX and .NET, so it will indeed be easier from there.

    You've used ShowModelessDialog() in your code, but I assume you mean ShowModalDialog(). Using a modeless dialog works fine for me as you've specified it.

    To get a modal dialog to work will take some more work. You can use DocumentManager.ExecuteInApplicationContext() from your command to specify a callback you want executed in the application context, and then hide your form. This will allow the callback to execute unhindered - otherwise it will only execute once your dialog has been closed by the user.

    From the callback you can use DocumentManager.Open() to open the drawings you want. After you're done you can simply use ShowModalDialog() to relaunch your dialog.

    This should work...

    Kean

  9. Are you able to read the RGB values and color names of "encrypted" Autodesk Colorbooks via the AutoCAD API?

  10. As far as I'm aware you should be able to use Color.FromNames() (it's been a long time since I've tried this, though).

    Kean

Leave a Reply to Kean Walmsley Cancel reply

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