« July 2007 | Main | September 2007 »

"Creating an Installer" webcast recording available for download

The recording of the latest in the AutoCAD Development Masterclass series, "Creating an Installer" held on August 16, has been posted here. The supporting MSI template used in the session is available from here.

The next in the series, "10 easy ways to crash your AutoCAD addin", is scheduled for Thursday September 27. You can go here to register (like all in this series, this session is free for all to attend).

August 31, 2007 in AutoCAD, Training | Permalink | Comments (3) | TrackBack

Autodesk University 2007 Developer Track

As mentioned some time ago, my team has been working with members of our Engineering teams to put together a comprehensive "Developer" track for AU 2007. We have 52 sessions devoted to developers or people customizing our products, in addition to a further 96 sessions in the "Customization and Programming" track. This adds up to host of great content for developers at this year's Autodesk University.

Below are the details of the various sessions in the "Developer" track. I've marked the course IDs of sessions that have already sold out in red and the guest speakers from Engineering in italics. There are three panel discussions where you can come along and get your development-oriented questions answered by experts from DevTech and Engineering. The sessions are filling up quickly (including the ones I'm presenting, thankfully :-) so please sign up soon.

I've created a "Through the Interface" group in AU Online (go to the Network tab). For those of you attending AU, please join the group. I'm looking forward to meeting many of you at AU!

Before I sign off, a quick reminder about our DevCamps... we have our AEC DevCamp next week and our Manufacturing DevCamp later in September. There is still time to sign up (depending on when you're reading this, of course :-).

Platforms (AutoCAD, RealDWG, AutoCAD OEM, DWF)
 
DE105-2 AutoCAD® APIs: The Right Tools for the Job Fenton Webb
DE111-2 AutoCAD® .NET Basics, Part I Stephen Preston
DE115-2 AutoCAD® .NET Basics, Part II Stephen Preston
DE201-2 AutoCAD® .NET: Tell Me About It! Stephen Preston
DE205-2 AutoCAD® .NET Show and Tell Gopinath Taget
DE211-2 The Best of Both Worlds: .NET and LISP Can Coexist Wayne Brill
DE215-2 Ask the Experts: ObjectARX® and AutoCAD® .NET Panel Discussion Panel of experts
DE219-2 Data, Data, Everywhere: Storing Your Custom Data in a .DWG Davis Augustine
DE305-2 Everything You Wanted to Know About Custom Entities but Were Too Afraid to Ask Fenton Webb
DE311-2 Signed, Sealed, and Delivered: Writing an Installer for Your AutoCAD® Application Fenton Webb
DE315-2 Ten Ways to Crash Your AutoCAD® Add-In Gopinath Taget
DE319-2 There's More to .DWG Than AutoCAD® Kean Walmsley
DE401-2 Enriching Your DWF™ Kean Walmsley
 
AEC (Architecture, Engineering & Construction)
 
DE105-1 The ABCs of Programming in Revit® Architecture, Revit® Structure, and Revit® MEP Jeremy Tammik
DE111-1 The Autodesk® Revit® SDK Sample Smörgåsbord Jeremy Tammik
DE115-1 Ten Steps for Enhancing Your Autodesk® Revit® Add-In Jeremy Tammik
DE201-1 Create Your Own Bidirectional Revit® Structure Stress Analysis Integration Link Jeremy Tammik
DE205-1 Reinforce Your Design: Revit® Structure API for Rebar and Detailing Jeremy Tammik
DE211-1 AutoCAD® Architecture and AutoCAD® MEP .NET Programming: A Beginner’s Guide Kevin Vandecar
DE215-1 An In-Depth Look at AutoCAD® Architecture .NET Programming Kevin Vandecar
DE219-1 Using the AEC Details Framework in AutoCAD® Architecture Mikako Harada
DE305-1 A Closer Look at the Revit® Database with the Revit API Mikako Harada
DE311-1 An In-Depth Look at AutoCAD® MEP .NET Programming Steve Milligan
DE315-1 Answers to Your API Questions: Experts Talk About Revit® and AutoCAD® Architecture & MEP APIs Panel of experts
DE401-1 Into the Vortex: A Whirlwind Overview of Programming with Autodesk® 3ds Max®, Part I Jean-Francois Yelle
DE405-1 Into the Vortex: A Whirlwind Overview of Programming with Autodesk® 3ds Max®, Part II Jean-Francois Yelle
 
Manufacturing
 
DE105-4 Turbo Charge Autodesk® Inventor™ with Its API Wayne Brill
DE111-4 Batch Those Autodesk® Inventor™ Drawings! Wayne Brill
DE115-4 Autodesk® Inventor™ Part APIs: Customizing the Building Blocks of Autodesk Inventor Models Wayne Brill
DE201-4 Autodesk® Inventor™ Assembly APIs: Bolt Together Inventor Models Automatically! Wayne Brill
DE205-4 Taking the Step from VBA to Autodesk® Inventor™ Add-Ins Brian Ekins
DE211-4 Industrial Strength Add-Ins: Creating Commands in Autodesk® Inventor™ Brian Ekins
DE215-4 Autodesk® Inventor™ API: The Cutting Edge Brian Ekins
DE219-4 Hardball with the Autodesk® Inventor™ API Brian Ekins
DE305-4 An Introduction to the Autodesk® Vault API Doug Redmond
DE311-4 Digital Matchmaking: Using the Autodesk® Productstream® API to Integrate with Other Systems Doug Redmond
DE315-4 Introducing the AutoCAD® Mechanical API Wayne Brill
DE319-4 Introducing the AutoCAD® Electrical API Nate Holt
DE401-4 Ask the Experts About Manufacturing APIs Panel of experts
 
Geospatial
 
DE105-3 Taking Geospatial Data Access to the Next Level with the FDO API Dongjin Xing
DE111-3 Getting Started with Autodesk MapGuide® Enterprise API Programming Dongjin Xing
DE115-3 Be Smart: Manage Those Resources with Autodesk MapGuide® Enterprise Dongjin Xing
DE201-3 Seek and You Shall Find: Query and Selection Through the Autodesk MapGuide® Enterprise API Dongjin Xing
DE205-3 Editing Data Online with the Autodesk MapGuide® Enterprise API Dongjin Xing
DE211-3 You Can Develop AutoCAD® Civil 3D® Applications, Too! Partha Sarkar
DE215-3 Come Up for Air: Learn to Surface with the AutoCAD® Civil 3D® API Partha Sarkar
DE219-3 Get Aligned with the AutoCAD® Civil 3D® API and Raise Your Profile Partha Sarkar
DE305-3 Design Your Own Custom AutoCAD® Civil 3D® Subassemblies Using .NET Partha Sarkar
DE311-3 AutoCAD® Map 3D API: Present and Future Dongjin Xing
DE315-3 Working with the AutoCAD® Map 3D Geospatial Platform API Dongjin Xing
DE319-3 Autodesk® Topobase™ API: Optimizing Spatial Data Access and Management Partha Sarkar
DE401-3 Taking a Closer Look at the Autodesk® Topobase™ API Partha Sarkar

August 30, 2007 in Training | Permalink | Comments (2) | TrackBack

Updating an Excel spreadsheet from a linked AutoCAD table using .NET

In the last post we saw some code to update an AutoCAD table linked to an Excel spreadsheet. In this post we go the other way, updating an Excel spreadsheet from a linked AutoCAD table.

Here's the C# code:

using Autodesk.AutoCAD.ApplicationServices;

using Autodesk.AutoCAD.DatabaseServices;

using Autodesk.AutoCAD.EditorInput;

using Autodesk.AutoCAD.Runtime;

using Autodesk.AutoCAD.Windows;


namespace LinkToExcel

{

  public class Commands

  {

    [CommandMethod("T2S")]

    static public void UpdateSpreadsheetFromTable()

    {

      Document doc =

        Application.DocumentManager.MdiActiveDocument;

      Database db = doc.Database;

      Editor ed = doc.Editor;


      PromptEntityOptions opt =

        new PromptEntityOptions(

          "\nSelect table with spreadsheet to update: "

        );

      opt.SetRejectMessage(

        "\nEntity is not a table."

      );

      opt.AddAllowedClass(typeof(Table), false);

      PromptEntityResult per =

        ed.GetEntity(opt);

      if (per.Status != PromptStatus.OK)

        return;


      Transaction tr =

        db.TransactionManager.StartTransaction();

      using (tr)

      {

        try

        {

          DBObject obj =

            tr.GetObject(

              per.ObjectId,

              OpenMode.ForRead

            );

          Table tb = (Table)obj;


          // It should always be a table

          // but we'll check, just in case


          if (tb != null)

          {

            // The table must be open for write


            tb.UpgradeOpen();


            // Update the data link from the table


            tb.UpdateDataLink(

              UpdateDirection.DataToSource,

              UpdateOption.ForceFullSourceUpdate

            );


            // And the spreadsheet from the data link


            ObjectId dlId = tb.GetDataLink(0, 0);

            DataLink dl =

              (DataLink)tr.GetObject(

                dlId,

                OpenMode.ForWrite

              );

            dl.Update(

              UpdateDirection.DataToSource,

              UpdateOption.ForceFullSourceUpdate

            );

          }

          tr.Commit();

          ed.WriteMessage(

            "\nUpdated the spreadsheet from the table."

          );

        }

        catch (Exception ex)

        {

          ed.WriteMessage(

            "\nException: {0}",

            ex.Message

          );

        }

      }

    }

  }

}

Tables with linked spreadsheets are locked by default and display this glyph when you hover over them: Locked_table. Before you run the code you will need to unlock the table by right-clicking the cell(s) you wish to edit:

Unlocking_the_table

One point to note is that the code will work even if the spreadsheet is open in Excel, but the contents will not be updated automatically - you have to close and reopen the file to see the results. And you will probably see this dialog come up twice:

Overwrite_spreadsheet

For the best (most logical) results, the T2S command should really be run when the spreadsheet is not open in Excel. I expect it's possible to determine whether a spreadsheet is open in Excel from using standard file access functions in .NET (requesting exclusive access, to see whether it's possible to get it), but that's being left as an exercise for the reader (or for another day, at least :-).

For your convenience, here's a source file containing the code from the last three posts (command implementations for TFS, S2T and T2S).

August 27, 2007 in AutoCAD, AutoCAD .NET, Excel, Tables | Permalink | Comments (0) | TrackBack

Updating an AutoCAD table linked to an Excel spreadsheet using .NET

Thanks to Viru Aithal, from DevTech India, for providing the code for this post (I converted the C# code below from some C++ he had sent to a developer).

In the last post we showed how to create a table linked to an Excel spreadsheet using .NET in AutoCAD 2008. AutoCAD does a great job of looking for changes in the Excel spreadsheet, and asking whether you want to update the linked table:

Data_link_changed_notification_2

There may be times, however, when you want to force the update programmatically, whether from the spreadsheet to the table ot vice-versa. In this post we'll show the code to update the table from the spreadsheet, and in the next post we'll see some code to update the spreadsheet from the table (should it have been unlocked and edited).

Here's the C# code:

using Autodesk.AutoCAD.ApplicationServices;

using Autodesk.AutoCAD.DatabaseServices;

using Autodesk.AutoCAD.EditorInput;

using Autodesk.AutoCAD.Runtime;


namespace LinkToExcel

{

  public class Commands

  {

    [CommandMethod("S2T")]

    static public void UpdateTableFromSpreadsheet()

    {

      Document doc =

        Application.DocumentManager.MdiActiveDocument;

      Database db = doc.Database;

      Editor ed = doc.Editor;


      PromptEntityOptions opt =

        new PromptEntityOptions(

          "\nSelect table to update: "

        );

      opt.SetRejectMessage(

        "\nEntity is not a table."

      );

      opt.AddAllowedClass(typeof(Table), false);

      PromptEntityResult per =

        ed.GetEntity(opt);

      if (per.Status != PromptStatus.OK)

        return;


      Transaction tr =

        db.TransactionManager.StartTransaction();

      using (tr)

      {

        try

        {

          DBObject obj =

            tr.GetObject(

              per.ObjectId,

              OpenMode.ForRead

            );

          Table tb = (Table)obj;


          // It should always be a table

          // but we'll check, just in case


          if (tb != null)

          {

            // The table must be open for write


            tb.UpgradeOpen();


            // Update the data link from the spreadsheet


            ObjectId dlId = tb.GetDataLink(0, 0);

            DataLink dl =

              (DataLink)tr.GetObject(

                dlId,

                OpenMode.ForWrite

              );

            dl.Update(

              UpdateDirection.SourceToData,

              UpdateOption.None

            );


            // And the table from the data link


            tb.UpdateDataLink(

              UpdateDirection.SourceToData,

              UpdateOption.None

            );

          }

          tr.Commit();

          ed.WriteMessage(

            "\nUpdated the table from the spreadsheet."

          );

        }

        catch (Exception ex)

        {

          ed.WriteMessage(

            "\nException: {0}",

            ex.Message

          );

        }

      }

    }

  }

}

When you run the S2T (for Spreadsheet-to-Table) command, you will be prompted to select a table. The code retrieves the link information from the table and then requests the data link to pull down new data from the spreadsheet before updating the table. Next time we'll look at the code for T2S...

August 24, 2007 in AutoCAD, AutoCAD .NET, Excel, Tables | Permalink | Comments (4) | TrackBack

Creating an AutoCAD table linked to an Excel spreadsheet using .NET

In the last post I promised to tackle this issue, and so here we are again. :-)

Note: the code in this post relies on enhanced table functionality introduced in AutoCAD 2008, so please don't get frustrated trying to make this work in previous versions.

The following C# code follows on from yesterday's, taking the spreadsheet selected by the user and linking it to a newly-created table in the active AutoCAD drawing. I haven't bothered with line numbering in the below code, as it follows on almost exactly from the code shown last time (aside from renaming the namespace, the command and the function, as well as adding a string constant at the top of the function implementation).

using Autodesk.AutoCAD.ApplicationServices;

using Autodesk.AutoCAD.DatabaseServices;

using Autodesk.AutoCAD.EditorInput;

using Autodesk.AutoCAD.Runtime;

using Autodesk.AutoCAD.Windows;


namespace LinkToExcel

{

  public class Commands

  {

    [CommandMethod("TFS")]

    static public void TableFromSpreadsheet()

    {

      // Hardcoding the string

      // Could also select for it

      const string dlName =

        "Import table from Excel demo";


      Document doc =

        Application.DocumentManager.MdiActiveDocument;

      Database db = doc.Database;

      Editor ed = doc.Editor;


      OpenFileDialog ofd =

        new OpenFileDialog(

          "Select Excel spreadsheet to link",

          null,

          "xls; xlsx",

          "ExcelFileToLink",

          OpenFileDialog.OpenFileDialogFlags.

            DoNotTransferRemoteFiles

        );


      System.Windows.Forms.DialogResult dr =

        ofd.ShowDialog();


      if (dr != System.Windows.Forms.DialogResult.OK)

        return;


      ed.WriteMessage(

        "\nFile selected was \"{0}\".",

        ofd.Filename

      );


      PromptPointResult ppr =

        ed.GetPoint(

          "\nEnter table insertion point: "

        );

      if (ppr.Status != PromptStatus.OK)

        return;


      // Remove the Data Link, if it exists already


      DataLinkManager dlm = db.DataLinkManager;

      ObjectId dlId = dlm.GetDataLink(dlName);

      if (dlId != ObjectId.Null)

      {

        dlm.RemoveDataLink(dlId);

      }


      // Create and add the Data Link


      DataLink dl = new DataLink();

      dl.DataAdapterId = "AcExcel";

      dl.Name = dlName;

      dl.Description =

        "Excel fun with Through the Interface";

      dl.ConnectionString = ofd.Filename;

      dl.DataLinkOption =

        DataLinkOption.PersistCache;

      dl.UpdateOption |=

        (int)UpdateOption.AllowSourceUpdate;


      dlId = dlm.AddDataLink(dl);


      Transaction tr =

        doc.TransactionManager.StartTransaction();

      using (tr)

      {

        tr.AddNewlyCreatedDBObject(dl, true);


        BlockTable bt =

          (BlockTable)tr.GetObject(

            db.BlockTableId,

            OpenMode.ForRead

          );


        Table tb = new Table();

        tb.TableStyle = db.Tablestyle;

        tb.Position = ppr.Value;

        tb.SetDataLink(0, 0, dlId, true);

        tb.GenerateLayout();


        BlockTableRecord btr =

          (BlockTableRecord)tr.GetObject(

            db.CurrentSpaceId,

            OpenMode.ForWrite

          );


        btr.AppendEntity(tb);

        tr.AddNewlyCreatedDBObject(tb, true);

        tr.Commit();

      }


      // Force a regen to display the table

      ed.Regen();

    }

  }

}

Here's what happens when you run the TFS command and select your favourite XLS for linking (I used mass-balance.xls from AutoCAD 2008's Sample\Mechanical Sample folder):

Table_linked_to_excel_spreadsheet

At this stage I haven't focused at all on formating - this is just coming in "as is", without any adjustment of cell alignments, column widths or row heights.

I chose to hardcode the name of the Data Link we use for the spreadsheet. You can run the DATALINK command to check on it, after the command has executed:

Data_link_for_excel_speadsheet_2 

It doesn't seem to be an issue if you repeat the command and bring in a different spreadsheet using the same link - the link appears to continue (although I haven't performed exhaustive testing). If it does prove to be a problem it should be simple enough to create a unique Data Link per spreadsheet imported (or even per time the command is run).

August 22, 2007 in AutoCAD, AutoCAD .NET, Excel, Tables | Permalink | Comments (0) | TrackBack

Using AutoCAD's file selection dialog from .NET

Today I started putting together some code showing how to link an Excel sheet to an AutoCAD table (watch this space - there should be something posted later this week). As I was working through it I decided enough was enough, and rather than - yet again - using the command-line to get the name of the file, I'd use the opportunity to demonstrate how to make use of AutoCAD's standard file selection dialog in your applications.

At which point I decided to cut the original post short, as I didn't want this useful (but quite short) topic to get swamped by the broader one.

Here's the C# code that asks the user to select an Excel spreadsheet:

using Autodesk.AutoCAD.ApplicationServices;

using Autodesk.AutoCAD.DatabaseServices;

using Autodesk.AutoCAD.EditorInput;

using Autodesk.AutoCAD.Runtime;

using Autodesk.AutoCAD.Windows;

namespace OpenFiles

{

  public class Commands

  {

    [CommandMethod("SS")]

    static public void SelectSpreadsheet()

    {

      Document doc =

        Application.DocumentManager.MdiActiveDocument;

      Database db = doc.Database;

      Editor ed = doc.Editor;

      OpenFileDialog ofd =

        new OpenFileDialog(

          "Select Excel spreadsheet to link",

          null,

          "xls; xlsx",

          "ExcelFileToLink",

          OpenFileDialog.OpenFileDialogFlags.DoNotTransferRemoteFiles

        );

      System.Windows.Forms.DialogResult dr =

        ofd.ShowDialog();

      if (dr != System.Windows.Forms.DialogResult.OK)

        return;

      ed.WriteMessage(

        "\nFile selected was \"{0}\".",

        ofd.Filename

      );

    }

  }

}

A few notes on the arguments to the OpenFileDialog constructor:

  1. The first string is the one shown in the title bar (see below)
  2. You can pass in a default filename in the second argument, but in our case it isn't appropriate
  3. You can provide multiple file extensions upon which to filter in the third argument, separated by semi-colons
  4. The fourth argument is an internal identifier used to store data about the dialog, such as size, position and last navigated path (this data will be picked up automatically the next time the identifier is used)
  5. The fifth argument is for flags: we're choosing not to copy remote files locally if selected via a URL, in this case

If we were opting to allow multiple file selection (passing AllowMultiple as an additional flag to the fifth argument), then we would access the files returned using ofd.GetFileNames() to access an array of strings.

Here's the dialog we see when we run the SS command:

Open_file_dialog

August 21, 2007 in AutoCAD, AutoCAD .NET, User interface | Permalink | Comments (11) | TrackBack

CommandComplete bonus tool

Most members of my team (DevTech) have a background in software development, having developed code professionally in previous jobs. People often join DevTech because they enjoy the variety and flexibility the role brings as well as the direct communication we have with the Autodesk development community.

That said, we still like to hone our coding skills - some of this we get from fielding questions we receive from ADN members but it's also helpful to work on the odd software project. Back in the day - during my stint living in India - DevTech was part of Autodesk Consulting and so members of the team were often involved in developing code for customers. These days our mandate is clearer, to focus on providing services through the Autodesk Developer Network.

The majority of the software projects we currently work on are samples for publication, whether as DevNotes on the ADN site or as samples we ship with the ObjectARX SDK. During the last year or so we've been running an internal initiative called "DevTech Labs", through which we develop customer-oriented features and bonus tools for posting to Autodesk Labs.

The first fruit of these labours is now available: the CommandComplete bonus tool. Sreekar Devatha, a member of the DevTech team based in India, was the primary developer on this project. I think he's done a great job on this very useful tool. :-)

This post from Scott Sheppard lists some of the feedback we've received to date. There's also further feedback received by email and the discussion group that we'll take into account when working on an update to this tool.

August 17, 2007 in AutoCAD, Commands | Permalink | Comments (0) | TrackBack

Purging registered application names from a folder of AutoCAD drawings using .NET

In the last post we looked at some code to programmatically purge Registered Application names from the drawing currently active in AutoCAD. In this post we take the "batching" code first used in this previous post and apply it to this problem.

What we end up with is an additional command called PF which asks the user to specify a folder and then purges the RegApps from the DWGs in that folder, saving those files that end up being modified with the "_purged" suffix.

One point to note is the use of the Database.RetainOriginalThumbnailBitmap property: as we're not making any graphical changes it's fairly safe to set this to true, which retains the pervious thumbnail bitmap, rather than it being blank in the new drawing. If you were to set it to true after graphical changes nothing especially serious would happen, but it could be confusing for users if the preview differed substantially from the DWG contents.

Here's the C# code with the additional lines in red:

    1 using Autodesk.AutoCAD.ApplicationServices;

    2 using Autodesk.AutoCAD.DatabaseServices;

    3 using Autodesk.AutoCAD.EditorInput;

    4 using Autodesk.AutoCAD.Runtime;

    5 using System.IO;

    6 using System;

    7

    8 namespace Purger

    9 {

   10   public class Commands

   11   {

   12     [CommandMethod("PF")]

   13     public void PurgeFiles()

   14     {

   15       Document doc =

   16         Application.DocumentManager.MdiActiveDocument;

   17       Editor ed = doc.Editor;

   18

   19       PromptResult pr =

   20         ed.GetString(

   21           "\nEnter folder containing DWGs to process: "

   22         );

   23       if (pr.Status != PromptStatus.OK)

   24         return;

   25       string pathName = pr.StringResult;

   26

   27       string[] fileNames =

   28         Directory.GetFiles(pathName, "*.dwg");

   29

   30       // We'll use some counters to keep track

   31       // of how the processing is going

   32

   33       int processed = 0, saved = 0, problem = 0;

   34

   35       foreach (string fileName in fileNames)

   36       {

   37         if (fileName.EndsWith(

   38               ".dwg",

   39               StringComparison.CurrentCultureIgnoreCase

   40             )

   41         )

   42         {

   43           string outputName =

   44             fileName.Substring(

   45               0,

   46               fileName.Length - 4) +

   47             "_purged.dwg";

   48           Database db = new Database(false, true);

   49           using (db)

   50           {

   51             try

   52             {

   53               ed.WriteMessage(

   54                 "\n\nProcessing file: " + fileName

   55               );

   56

   57               db.ReadDwgFile(

   58                 fileName,

   59                 FileShare.ReadWrite,

   60                 false,

   61                 ""

   62               );

   63

   64               db.RetainOriginalThumbnailBitmap = true;

   65

   66               int objectsPurged =

   67                 PurgeDatabase(db);

   68

   69               // Display the results

   70

   71               ed.WriteMessage(

   72                 "\nPurged {0} object{1}",

   73                 objectsPurged,

   74                 objectsPurged == 1 ? "" : "s"

   75               );

   76

   77               // Only save if we changed something

   78

   79               if (objectsPurged > 0)

   80               {

   81                 ed.WriteMessage(

   82                   "\nSaving to file: {0}", outputName

   83                 );

   84

   85                 db.SaveAs(

   86                   outputName,

   87                   DwgVersion.Current

   88                 );

   89                 saved++;

   90               }

   91               processed++;

   92             }

   93             catch (System.Exception ex)

   94             {

   95               ed.WriteMessage(

   96                 "\nProblem processing file: {0} - \"{1}\"",

   97                 fileName,

   98                 ex.Message

   99               );

  100               problem++;

  101             }

  102           }

  103         }

  104       }

  105       ed.WriteMessage(

  106         "\n\nSuccessfully processed {0} files," +

  107         " of which {1} had objects to purge" +

  108         " and an additional {2} had errors " +

  109         "during reading/processing.",

  110         processed,

  111         saved,

  112         problem

  113       );

  114     }

  115

  116     [CommandMethod("PC")]

  117     public void PurgeCurrentDocument()

  118     {

  119       Document doc =

  120         Application.DocumentManager.MdiActiveDocument;

  121       Database db = doc.Database;

  122       Editor ed = doc.Editor;

  123

  124       int count =

  125         PurgeDatabase(db);

  126

  127       ed.WriteMessage(

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

  129         "the current database.",

  130         count,

  131         count == 1 ? "" : "s"

  132       );

  133     }

  134

  135     private static int PurgeDatabase(Database db)

  136     {

  137       int idCount = 0;

  138

  139       Transaction tr =

  140         db.TransactionManager.StartTransaction();

  141       using (tr)

  142       {

  143         // Create the list of objects to "purge"

  144

  145         ObjectIdCollection idsToPurge =

  146           new ObjectIdCollection();

  147

  148         // Add all the Registered Application names

  149

  150         RegAppTable rat =

  151           (RegAppTable)tr.GetObject(

  152             db.RegAppTableId,

  153             OpenMode.ForRead

  154         );

  155

  156         foreach (ObjectId raId in rat)

  157         {

  158           if (raId.IsValid)

  159           {

  160             idsToPurge.Add(raId);

  161           }

  162         }

  163

  164         // Call the Purge function to filter the list

  165

  166         db.Purge(idsToPurge);

  167

  168         Document doc =

  169           Application.DocumentManager.MdiActiveDocument;

  170         Editor ed = doc.Editor;

  171

  172         ed.WriteMessage(

  173           "\nRegistered applications being purged: "

  174         );

  175

  176         // Erase each of the objects we've been

  177         // allowed to

  178

  179         foreach (ObjectId id in idsToPurge)

  180         {

  181           DBObject obj =

  182             tr.GetObject(id, OpenMode.ForWrite);

  183

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

  185           // to list the registered applications

  186           // we're erasing

  187

  188           RegAppTableRecord ratr =

  189             obj as RegAppTableRecord;

  190           if (ratr != null)

  191           {

  192             ed.WriteMessage(

  193               "\"{0}\" ",

  194               ratr.Name

  195             );

  196           }

  197

  198           obj.Erase();

  199         }

  200

  201         // Return the number of objects erased

  202         // (i.e. purged)

  203

  204         idCount = idsToPurge.Count;

  205         tr.Commit();

  206       }

  207       return idCount;

  208     }

  209   }

  210 }

You can download the source file from here.

August 15, 2007 in AutoCAD, AutoCAD .NET, Batch processing, Drawing structure, Purge | Permalink | Comments (10) | TrackBack

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