Purging registered application names in the current AutoCAD drawing using .NET

Purging can seriously reduce the size of AutoCAD drawings by removing unnecessary symbol table and dictionary entries. The PURGE command in AutoCAD allows you to safely purge these non-graphical objects (layers, linetypes, block definitions, etc.).

Since AutoCAD 2005 (if I recall correctly), PURGE also supports the removal of Registered Application names. Applications that make use of Extended Entity Data (XData) must register unique application names in drawings. A few applications have, in the past, created many more names than they required, and as these RegApp names get copied from drawing to drawing (when they get XRefed, for instance), they ended spreading from DWG file to DWG file (one comparison I remember hearing was to a virus, although that was perhaps a little extreme). To the best of my knowledge the applications that mistakenly caused this problem have now been fixed (and shall remain nameless), but there are still drawings out there with a lot of these records, which is ultimately why we extended PURGE to address the problem from within AutoCAD.

Anyway, I've chosen to implement a command to purge these RegApp names - even though it's now there in the product - really just an example of how to code this type of functionality. It could very easily be extended to handle the specific data you feel needs purging in your company's (or customers') DWG files.

The Database.Purge() function available in .NET wraps AcDbDatabase::purge(). These functions are both misleadingly named, as neither of them actually performs a purge on the database. What they do - and this is actually more useful, as it gives you more control - is filter a list of object IDs you pass in, removing any that cannot safely be purged by your application. So they would more accurately be named TellMeWhatCanSafelyBePurged(), or something like that. Typically objects get removed from the list because a reference exists somewhere in the drawing to that object - such as from an entity to a layer (making the layer dangerous to purge). The code calling the Purge function will usually then erase the objects that have been returned. And that's how the PURGE command is implemented.

Here's some C# code that purges the Registered Application names in the current document:

using Autodesk.AutoCAD.ApplicationServices;

using Autodesk.AutoCAD.DatabaseServices;

using Autodesk.AutoCAD.EditorInput;

using Autodesk.AutoCAD.Runtime;

using System.IO;

using System;

namespace Purger

{

  public class Commands

  {

    [CommandMethod("PC")]

    public void PurgeCurrentDocument()

    {

      Document doc =

        Application.DocumentManager.MdiActiveDocument;

      Database db = doc.Database;

      Editor ed = doc.Editor;

      int count =

        PurgeDatabase(db);

      ed.WriteMessage(

        "\nPurged {0} object{1} from " +

        "the current database.",

        count,

        count == 1 ? "" : "s"

      );

    }

    private static int PurgeDatabase(Database db)

    {

      int idCount = 0;

      Transaction tr =

        db.TransactionManager.StartTransaction();

      using (tr)

      {

        // Create the list of objects to "purge"

        ObjectIdCollection idsToPurge =

          new ObjectIdCollection();

        // Add all the Registered Application names

        RegAppTable rat =

          (RegAppTable)tr.GetObject(

            db.RegAppTableId,

            OpenMode.ForRead

        );

        foreach (ObjectId raId in rat)

        {

          if (raId.IsValid)

          {

            idsToPurge.Add(raId);

          }

        }

        // Call the Purge function to filter the list

        db.Purge(idsToPurge);

        Document doc =

          Application.DocumentManager.MdiActiveDocument;

        Editor ed = doc.Editor;

        ed.WriteMessage(

          "\nRegistered applications being purged: "

        );

        // Erase each of the objects we've been

        // allowed to

        foreach (ObjectId id in idsToPurge)

        {

          DBObject obj =

            tr.GetObject(id, OpenMode.ForWrite);

          // Let's just add to me "debug" code

          // to list the registered applications

          // we're erasing

          RegAppTableRecord ratr =

            obj as RegAppTableRecord;

          if (ratr != null)

          {

            ed.WriteMessage(

              "\"{0}\" ",

              ratr.Name

            );

          }

          obj.Erase();

        }

        // Return the number of objects erased

        // (i.e. purged)

        idCount = idsToPurge.Count;

        tr.Commit();

      }

      return idCount;

    }

  }

}

Here's what happens when you run the PC command:

Command: PC

Registered applications being purged: "AcadAnnoPO" "PE_URL" "AcadAnnoAV"

"ACAD_EXEMPT_FROM_CAD_STANDARDS"

Purged 4 objects from the current database.

In the next post we'll look at extending this to - once again - work on a folder of drawings.

15 responses to “Purging registered application names in the current AutoCAD drawing using .NET”

  1. Hey, thanks for hitting this subject Kean! If there is any chance you could comment on the possibility/difficulty of stopping reg apps in xrefs from "sticking" in drawings they are xreffed to, that would be appreciated. No worries if you cannot get to it, you already did a huge favor by these posts!

  2. Hi James,

    I can see a few ways to go about this:

    <ul>
    <li>Respond to events telling you when an xref is created - from here you can fire off the PC command to purge the current drawing (probably using SendStringToExecute()):</li>
    <ul>
    <li>the Editor.CommandEnded event for the XATTACH command</li>
    <li>the Database.ObjectAppended event for a block reference corresponding to an xref</li>
    </ul>
    <li>As a matter of course run the PC command (or the code it uses) just before a drawing is saved:</li>
    <ul>
    <li>redefine the QSAVE and SAVE commands to call PC first</li>
    <li>use the Database.BeginSave event (assuming that's not too late - this would need testing) to run the code from there</li>
    </ul>
    </ul>

    I'm sure there are options I've missed, but these are some of the different ways you might investigate automating this activity.

    Cheers,

    Kean

  3. Hi Kean,

    Could you please explain how we can redefine QSAVE?

    Thanks
    ss

  4. You undefine it with the UNDEFINE command, and implement your own command of that name.

    Kean

  5. How to get the VBA macro attached with a drawing?

  6. Kean Walmsley Avatar

    This isn't a VBA macro, so currently can't be attached with a drawing.

    Kean

  7. is there any api module available in Realdwg to detect VBA macro attached with a drawing..
    i tried Dictionary entry of "ACAD_VBA" which returns VBA manager object..... but how to type cast it?

    DBDictionary dic = tr.GetObject((ObjectId)nod.GetAt("ACAD_VBA"), OpenMode.ForRead) as DBDictionary;

    foreach (DictionaryEntry entry in dic)
    {

    object a = tr.GetObject((ObjectId)entry.Value, OpenMode.ForRead);
    }

  8. tArun -

    This is a question for the ADN team, if you're a member.

    Regards,

    Kean

  9. Dear Sir,

    I need to purge and Audit a set of autocad files by batch processing them and without opening the files.

    Above is the way to purge the files.
    how can I Audit a batch of autocad files?

    I am using db.Audit() which accepts AutitInfo as parameter. But I am not able to set the AuditInfo parameter or to define it.

    Please advise.

  10. Dear Mira,

    I haven't had to do this, myself: I suggest posting your question via the ADN site, if you're an ADN member, or to the AutoCAD .NET Discussion Group, otherwise.

    Regards,

    Kean

  11. hi kean,

    i would like to ask if u can give me some drawing examples of this commands? PSpace, QLeader, Purge, properties, Properties close..

    please its for my reporting..
    thanks kean..
    godbless!!!

  12. Hi Jessica,

    Sorry - firstly I don't really understand what you're asking, and secondly I don't have time to provide support that's unrelated to my posts (unless this is actually a suggestion for a blog post, which I unfortunately can't commit to addressing).

    I suggest posting your question to one of our online discussion groups.

    Kean

  13. Is the method included still compatible with the current 2020 or 2021 release of AutoCAD? It works fine if i have a drawing with only a couple dozen regapps in it, but I have files with over 500K and it seems to never finish. I can run the -Purge command and it finishes in 5 to 10 minutes but the included code will go all night and never finish. It does hold a single core of the processor at a steady ~12% but that is about it.
    Also I have noticed that when it is on a smaller file if Autosave runs after it is started it will jam things up, I have never had that before so should I be doing something with Autosave before running a command like this?

    1. Hi Mike,

      I honestly have no idea: this whole mechanism pre-dated the modifications to the -PURGE command. If -PURGE is working more reliably for you, then you should really use that.

      If you really want to get this code working, I suggest posting on the AutoCAD .NET forum, to see if someone there can help.

      Best,

      Kean

  14. بَحرانی اِحسان Avatar
    بَحرانی اِحسان

    hi
    how can find purgeable entities?

Leave a Reply to jessica Cancel reply

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