Application: AutoCAD .NET API
Category: Automation
Difficulty: Intermediate
Language: C#
You need to process multiple DWG files automatically - for example, updating block attributes, purging unused objects, or exporting data - without manually opening each file.
Use AutoCAD's Database class to open drawings in the background without displaying them in the UI. This approach is much faster than opening files through the UI and allows true batch processing.
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;
using System;
using System.IO;
[CommandMethod("BATCHPROCESS")]
public void BatchProcessDrawings()
{
Document doc = Application.DocumentManager.MdiActiveDocument;
Editor ed = doc.Editor;
// Get folder containing drawings
string folderPath = @"C:\Drawings\ToProcess";
if (!Directory.Exists(folderPath))
{
ed.WriteMessage("\nFolder not found!");
return;
}
// Get all DWG files
string[] dwgFiles = Directory.GetFiles(folderPath, "*.dwg");
ed.WriteMessage($"\nFound {dwgFiles.Length} drawings to process");
int successCount = 0;
int errorCount = 0;
foreach (string dwgPath in dwgFiles)
{
try
{
ed.WriteMessage($"\nProcessing: {Path.GetFileName(dwgPath)}");
// Open drawing in background (not in UI)
using (Database db = new Database(false, true))
{
db.ReadDwgFile(dwgPath, FileOpenMode.OpenForReadAndAllShare, false, "");
using (Transaction tr = db.TransactionManager.StartTransaction())
{
// Process the drawing
ProcessDrawing(db, tr);
tr.Commit();
}
// Save changes
db.SaveAs(dwgPath, DwgVersion.Current);
}
successCount++;
}
catch (Exception ex)
{
ed.WriteMessage($"\nError processing {Path.GetFileName(dwgPath)}: {ex.Message}");
errorCount++;
}
}
ed.WriteMessage($"\n\nBatch processing complete!");
ed.WriteMessage($"\nSuccessful: {successCount}");
ed.WriteMessage($"\nErrors: {errorCount}");
}
private void ProcessDrawing(Database db, Transaction tr)
{
// Example: Count and report block references
BlockTable bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
BlockTableRecord modelSpace = tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForRead) as BlockTableRecord;
int blockCount = 0;
foreach (ObjectId objId in modelSpace)
{
Entity ent = tr.GetObject(objId, OpenMode.ForRead) as Entity;
if (ent is BlockReference)
{
blockCount++;
}
}
// You can add any processing logic here:
// - Update block attributes
// - Purge unused layers
// - Export data to Excel
// - Modify text styles
// - etc.
}
using System.Collections.Generic;
using System.Text;
public class DrawingData
{
public string FileName { get; set; }
public int LayerCount { get; set; }
public int BlockCount { get; set; }
public int TextCount { get; set; }
}
[CommandMethod("EXTRACTDATA")]
public void ExtractDataFromDrawings()
{
Document doc = Application.DocumentManager.MdiActiveDocument;
Editor ed = doc.Editor;
string folderPath = @"C:\Drawings\ToAnalyze";
string[] dwgFiles = Directory.GetFiles(folderPath, "*.dwg");
List<DrawingData> dataList = new List<DrawingData>();
foreach (string dwgPath in dwgFiles)
{
try
{
using (Database db = new Database(false, true))
{
db.ReadDwgFile(dwgPath, FileOpenMode.OpenForReadAndAllShare, false, "");
using (Transaction tr = db.TransactionManager.StartTransaction())
{
DrawingData data = new DrawingData
{
FileName = Path.GetFileName(dwgPath)
};
// Count layers
LayerTable lt = tr.GetObject(db.LayerTableId, OpenMode.ForRead) as LayerTable;
data.LayerCount = lt.Count;
// Count blocks and text
BlockTable bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
BlockTableRecord modelSpace = tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForRead) as BlockTableRecord;
foreach (ObjectId objId in modelSpace)
{
Entity ent = tr.GetObject(objId, OpenMode.ForRead) as Entity;
if (ent is BlockReference) data.BlockCount++;
if (ent is DBText || ent is MText) data.TextCount++;
}
dataList.Add(data);
tr.Commit();
}
}
}
catch (Exception ex)
{
ed.WriteMessage($"\nError: {ex.Message}");
}
}
// Export to CSV
StringBuilder csv = new StringBuilder();
csv.AppendLine("File Name,Layers,Blocks,Text Objects");
foreach (var data in dataList)
{
csv.AppendLine($"{data.FileName},{data.LayerCount},{data.BlockCount},{data.TextCount}");
}
string csvPath = Path.Combine(folderPath, "DrawingAnalysis.csv");
File.WriteAllText(csvPath, csv.ToString());
ed.WriteMessage($"\nData exported to: {csvPath}");
}
Database.ReadDwgFile() to open drawings without UIusing statements to ensure proper disposalFileOpenMode.OpenForReadAndAllShare allows opening files that are open in other applicationsSaveAs() to save changes back to the fileDatabase.CloseInput(true) to release file handles immediatelydb.UndoRecording = falseMistake: Not disposing the database properly
// WRONG - memory leak
Database db = new Database(false, true);
db.ReadDwgFile(path, FileOpenMode.OpenForReadAndAllShare, false, "");
// Database never disposed!
// CORRECT
using (Database db = new Database(false, true))
{
db.ReadDwgFile(path, FileOpenMode.OpenForReadAndAllShare, false, "");
// Automatically disposed
}
Mistake: Opening files with wrong file mode
// WRONG - fails if file is open elsewhere
db.ReadDwgFile(path, FileOpenMode.OpenForReadAndWriteNoShare, false, "");
// CORRECT - allows shared access
db.ReadDwgFile(path, FileOpenMode.OpenForReadAndAllShare, false, "");
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;
using System;
using System.IO;
[CommandMethod("BATCHPROCESS")]
public void BatchProcessDrawings()
{
Document doc = Application.DocumentManager.MdiActiveDocument;
Editor ed = doc.Editor;
// Get folder containing drawings
string folderPath = @"C:\Drawings\ToProcess";
if (!Directory.Exists(folderPath))
{
ed.WriteMessage("\nFolder not found!");
return;
}
// Get all DWG files
string[] dwgFiles = Directory.GetFiles(folderPath, "*.dwg");
ed.WriteMessage($"\nFound {dwgFiles.Length} drawings to process");
int successCount = 0;
int errorCount = 0;
foreach (string dwgPath in dwgFiles)
{
try
{
ed.WriteMessage($"\nProcessing: {Path.GetFileName(dwgPath)}");
// Open drawing in background (not in UI)
using (Database db = new Database(false, true))
{
db.ReadDwgFile(dwgPath, FileOpenMode.OpenForReadAndAllShare, false, "");
using (Transaction tr = db.TransactionManager.StartTransaction())
{
// Process the drawing
ProcessDrawing(db, tr);
tr.Commit();
}
// Save changes
db.SaveAs(dwgPath, DwgVersion.Current);
}
successCount++;
}
catch (Exception ex)
{
ed.WriteMessage($"\nError processing {Path.GetFileName(dwgPath)}: {ex.Message}");
errorCount++;
}
}
ed.WriteMessage($"\n\nBatch processing complete!");
ed.WriteMessage($"\nSuccessful: {successCount}");
ed.WriteMessage($"\nErrors: {errorCount}");
}
private void ProcessDrawing(Database db, Transaction tr)
{
// Example: Count and report block references
BlockTable bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
BlockTableRecord modelSpace = tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForRead) as BlockTableRecord;
int blockCount = 0;
foreach (ObjectId objId in modelSpace)
{
Entity ent = tr.GetObject(objId, OpenMode.ForRead) as Entity;
if (ent is BlockReference)
{
blockCount++;
}
}
// You can add any processing logic here:
// - Update block attributes
// - Purge unused layers
// - Export data to Excel
// - Modify text styles
// - etc.
}