Менеджер пакетной обработки чертежей

Дата публикации: 22 июля 2010


Сразу хочу обратить внимание, что под термином "пакетная обработка чертежей" (в разрезе САПР AutoCAD) не стоит понимать лишь выполнение над файлами набора различных скриптов (scr-файлов). Этот термин имеет более широкое значение - над чертежами может потребоваться произвести более сложный набор задач, которые не всегда удастся выполнить с помощью скриптовых файлов (например выполнить анализ чертежей и выдать отчёт с результатами, либо проанализировав чертежи создать в них же различные сводные ведомости). 

Задача

Написать менеджер пакетной обработки чертежей AutoCAD (далее по тексту просто менеджер), в котором были бы реализованы следующие моменты:

1. Пользователь должен иметь возможность указывать перечень нуждающихся в обработке чертежей, одним из следующих способов:
    1.1. На основе каталога, заданного пользователем с указанием того, необходимо ли осуществлять рекурсивную выборку файлов по подкаталогам
    1.2. На основе указанного файла подшивки (dst-файла) - будут обработаны все чертежи в её составе.
    1.3. Набор файлов указывается пользователем вручную (индивидуально).
2.   Логика решения каждой задачи должна быть упакована в виде отдельного класса, реализующего определённый интерфейс. Такие объекты так и будем называть - задачами. Реализация чётко  определённого интерфейса предоставляет пользователям (коими в данном случае являются прикладные программисты) возможность самостоятельной разработке своих вариантов решения различных задач. Потом рядовые пользователи AutoCAD смогут их использовать.
3.   Каждая задача должна решать только одну чётко определённую проблему и ничего кроме этого.
4.   Каждая задача должна вести свой собственный журнал хода выполнения процесса решения. Данный журнал представлен одним из свойств интерфейса, обозначенного в п.2.
5.   Менеджер должен уметь вызывать на исполнение любые операции представленные классами, обозначенными в п.2.
6.   Менеджер должен вести общий журнал хода пакетной обработки, в котором были бы собраны журналы всех задач, вызванных в рамках текущей сессии.
7.   Все журналы, упомянутые в п.5 и п.7 должны вестись в формате XML, дабы их было легко обрабатывать программно.
8.   Менеджер должен иметь удобный и понятный графический интерфейс (GUI), разработанный средствами WPF.
9.   В менеджере должна присутствовать возможность выбора нужной локализации.

Реализация п. 8 и 9 в рамках данной статьи пока не рассматриваются, т.к. разработка GUI для меня сейчас не является приоритетной задачей (не хватает свободного времени).

Решение

Разрабатываемый менеджер будет представлять собой плагин (dll-файл) к AutoCAD, т.к. реализация его в виде отдельного приложения не позволит использовать библиотеку, через которую можно работать с подшивками. 

Визуально набор необходимых классов будет выглядеть так:


IDwgOperation - интерфейс, который должны реализовывать все классы, в которых инкапсулирована логика выполняемой операции

DwgOperation - абстрактный класс, в котором реализован общий код, который пришлось бы писать в каждом классе операции. Я рекомендую классы операций создавать не с нуля, реализуя интерфейс IDwgOperation самостоятельно, а наследоваться от абстрактного класса DwgOperation, переопределяя ряд его методов.

DrawingSearcher - класс, с помощью которого выполняется поиск файлов, над которыми следует выполнить набор операций. Поиск может осуществляться как по каталогам, так и по подшивкам. В случае необходимости поиск может выполняться рекурсивно.

BatchManager - класс, с помощью которого выполняется пакетная обработка файлов.

RunScriptFiles - класс, в котором инкапсулирована логика запуска скриптов. Данный класс создан в качестве примера того, как можно создавать классы операций, наследуясь от абстрактного класса DwgOperation.

Далее опубликовываю исходники:

1. Интерфейс IDwgOperation:

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Linq;
   4:  using System.Text;
   5:  using System.IO;
   6:  //AutoCAD
   7:  using Autodesk.AutoCAD.ApplicationServices;
   8:  using System.Xml.Linq;
   9:  using Autodesk.AutoCAD.DatabaseServices;
  10:   
  11:  namespace AcadBatchProcessing
  12:  {
  13:      /// <summary>
  14:      /// Действие, программно выполняемое над файлом чертежа (dwg/dwt/dws).
  15:      /// </summary>
  16:      public interface IDwgOperation
  17:      {
  18:          /// <summary>
  19:          /// Чертёж, над которым должно выполняться действие
  20:          /// </summary>
  21:          Document Drawing { get; set; }
  22:   
  23:          /// <summary>
  24:          /// Набор дополнительных параметров. Если параметры не нужны, следует передавать null.
  25:          /// </summary>
  26:          object[] Parameters { get; }
  27:   
  28:          /// <summary>
  29:          /// Наименование выполняемой операции
  30:          /// </summary>
  31:          string OperationName
  32:          {
  33:              get;            
  34:          }       
  35:   
  36:          /// <summary>
  37:          /// Описание выполняемой операции
  38:          /// </summary>
  39:          string Description
  40:          {
  41:              get;            
  42:          }
  43:   
  44:          /// <summary>
  45:          /// Выполняемое действие
  46:          /// </summary>
  47:          void Run();
  48:      }
  49:  }

2. Абстрактный класс DwgOperation:

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Linq;
   4:  using System.Text;
   5:  using Autodesk.AutoCAD.ApplicationServices;
   6:  using Autodesk.AutoCAD.EditorInput;
   7:  using Autodesk.AutoCAD.DatabaseServices;
   8:  using System.IO;
   9:  using System.Xml.Linq;
  10:   
  11:  namespace AcadBatchProcessing
  12:  {
  13:      /// <summary>
  14:      /// Абстрактный класс операции, программно производимой с файлом чертежа
  15:      /// </summary>
  16:      public abstract class DwgOperation : IDwgOperation
  17:      {
  18:          Document dwg;
  19:          object[] parameters;
  20:   
  21:          /// <summary>
  22:          /// Конструктор объекта
  23:          /// </summary>
  24:          /// <param name="parameters">Набор дополнительных параметров. Если параметры не нужны, следует передавать null.</param>
  25:          public DwgOperation(object[] parameters)
  26:          {
  27:              OperationName = string.Empty;
  28:              Description = string.Empty;
  29:              this.parameters = parameters;
  30:          }
  31:   
  32:          /// <summary>
  33:          /// Выполняемая операция
  34:          /// </summary>
  35:          public virtual void Run()
  36:          {
  37:              throw new NotImplementedException();
  38:          }
  39:   
  40:          /// <summary>
  41:          /// База данных чертежа, над которым выполняется операция
  42:          /// </summary>
  43:          public Document Drawing
  44:          {
  45:              get { return dwg; }
  46:              set { dwg = value;
  47:              }
  48:          }
  49:   
  50:          /// <summary>
  51:          /// Набор дополнительных параметров. Если параметры не нужны, следует передавать null.
  52:          /// </summary>
  53:          public object[] Parameters
  54:          {
  55:              get { return parameters; }
  56:          }
  57:   
  58:          string operationName;
  59:          string description;
  60:   
  61:          public string OperationName
  62:          {
  63:              get
  64:              {
  65:                  return operationName;
  66:              }
  67:              internal set
  68:              {
  69:                  operationName = value;
  70:              }
  71:          }
  72:          /// <summary>
  73:          /// Описание выполняемой операции
  74:          /// </summary>
  75:          public string Description
  76:          {
  77:              get
  78:              {
  79:                  return description;
  80:              }
  81:              internal set
  82:              {
  83:                  description = value;
  84:              }
  85:          }
  86:      }
  87:  }

3. Класс DrawingSearcher:

   1:  using Autodesk.AutoCAD.ApplicationServices;
   2:  using Autodesk.AutoCAD.EditorInput;
   3:  using Autodesk.AutoCAD.Runtime;
   4:  using Autodesk.AutoCAD.Windows;
   5:  using acad = Autodesk.AutoCAD.ApplicationServices.Application;
   6:  using ACSMCOMPONENTS17Lib;
   7:  using System.Windows.Forms;
   8:  using System;
   9:  using System.IO;
  10:  using System.Linq;
  11:  using System.Collections.Generic;
  12:   
  13:  namespace AcadBatchProcessing
  14:  {
  15:      public sealed class DrawingSearcher
  16:      {
  17:          string drawingExtensionFilter = "*.dwg";
  18:   
  19:          /// <summary>
  20:          /// Типы файлов, которые необходимо обрабатывать в поиске
  21:          /// </summary>
  22:          public string FileExtensionsFilter
  23:          {
  24:              get { return drawingExtensionFilter; }
  25:              set { drawingExtensionFilter = value; }
  26:          }
  27:          Editor ed = acad.DocumentManager.MdiActiveDocument.Editor;
  28:   
  29:          /// <summary>
  30:          /// Получение файлов чертежей, входящих в состав определённой подшивки
  31:          /// </summary>
  32:          /// <param name="DstFileFullName">Полное имя файла подшивки</param>
  33:          /// <returns>Возвращается перечисление объектов FileInfo</returns>
  34:          public List<FileInfo> GetSheetSetDrawings(string DstFileFullName)
  35:          {
  36:              List<FileInfo> x = new List<FileInfo>();
  37:              //********************
  38:              // Получаем менеджера подшивки
  39:              AcSmSheetSetMgr mgr = new AcSmSheetSetMgr();
  40:   
  41:              // Создаём новый объект базы данных подшивки
  42:              AcSmDatabase db = new AcSmDatabase();
  43:   
  44:              // Пытаемся загрузить dst-файл 
  45:              try
  46:              {
  47:                  db = mgr.OpenDatabase(DstFileFullName, true);
  48:              }
  49:              catch (System.Exception ex)
  50:              {
  51:                  ed.WriteMessage(ex.ToString());
  52:                  return null;
  53:              }
  54:   
  55:              try
  56:              {
  57:                  // На время блокируем базу данных подшивки от изменения извне
  58:                  db.LockDb(db);
  59:   
  60:                  AcSmSheetSet ss = db.GetSheetSet();                
  61:                  ProcessEnumerator(ss.GetSheetEnumerator(), ref x);
  62:              }
  63:              catch (System.Exception ex)
  64:              {
  65:                  ed.WriteMessage("\nНе удалось заблокировать подшивку - возможно она кем-то открыта в данный момент");
  66:                  ed.WriteMessage("\n" + ex.Message);
  67:              }
  68:              //Снимаем блокировку базы данных подшивки
  69:              finally
  70:              {
  71:                  db.UnlockDb(db, true);
  72:                  mgr.Close(db);
  73:              }
  74:              return x;
  75:          }
  76:   
  77:          /// <summary>
  78:          /// Получение всех чертежей, хранящихся в определённом каталоге
  79:          /// </summary>
  80:          /// <param name="directoryFullName">Полное имя каталога</param>
  81:          /// <param name="subDirsBrowse">Выполнять ли поиск по подкаталагам (True - выполнять; False - не выполнять)</param>
  82:          /// <returns>Возвращается последовательностьFileInfo</returns>
  83:          public IEnumerable<FileInfo> GetDrawingsFromDirectory(string directoryFullName, bool subDirsBrowse)
  84:          {
  85:              DirectoryInfo dir = new DirectoryInfo(directoryFullName);
  86:              if (!dir.Exists) throw new DirectoryNotFoundException();
  87:              return dir.GetFiles(drawingExtensionFilter, subDirsBrowse ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly)
  88:                  .AsEnumerable().OrderBy(n => n.DirectoryName).ThenBy(n => n.Name).ThenBy(n => n.Extension);           
  89:          }
  90:   
  91:          /// <summary>
  92:          /// Извлечение полных имён файлов, включенных в состав подшивки
  93:          /// </summary>
  94:          /// <param name="iter">Родительский объект</param>
  95:          /// <param name="x">ссылка на объект List<FileInfo>, в котором инкапсулирован результат</param>
  96:          void ProcessEnumerator(IAcSmEnumComponent iter, ref List<FileInfo> x)
  97:          {
  98:              IAcSmComponent item = iter.Next();
  99:              while (item != null)
 100:              {
 101:                  string type = item.GetTypeName();                
 102:                  switch (type)
 103:                  {
 104:                      //Группа листов (рекурсивная обработка, т.к. может содержать вложенные группы листов)
 105:                      case "AcSmSubset":
 106:                          try
 107:                          {
 108:                              AcSmSubset subset = (AcSmSubset)item;
 109:                              string subName = subset.GetName();
 110:   
 111:                              if (!String.IsNullOrEmpty(subName))
 112:                              {                               
 113:                                  IAcSmEnumComponent enumerator = (IAcSmEnumComponent)subset.GetSheetEnumerator();
 114:                                  ProcessEnumerator(enumerator, ref x);
 115:                              }
 116:                          }
 117:                          catch { }
 118:                          break;
 119:   
 120:                      //Лист
 121:                      case "AcSmSheet":
 122:                          try
 123:                          {
 124:                              AcSmSheet sh = (AcSmSheet)item;
 125:                              x.Add(new FileInfo(sh.GetLayout().GetFileName()));
 126:                              if (!String.IsNullOrEmpty(sh.GetName()))
 127:                              {
 128:                                  IAcSmEnumComponent enumerator = (IAcSmEnumComponent)sh.GetSheetViews();
 129:                                  ProcessEnumerator(enumerator, ref x);
 130:                              }
 131:                          }
 132:                          catch { }
 133:                          break;
 134:                  }
 135:                  item = iter.Next();
 136:              }
 137:          }
 138:      }
 139:  }

4. Класс BatchManager:

   1:  //Common
   2:  using System;
   3:  using System.IO;
   4:  using System.Linq;
   5:  using System.Xml.Linq;
   6:  using System.Collections.Generic;
   7:  //AutoCAD
   8:  using Autodesk.AutoCAD.ApplicationServices;
   9:  using Autodesk.AutoCAD.EditorInput;
  10:  using Autodesk.AutoCAD.Runtime;
  11:  using Autodesk.AutoCAD.Windows;
  12:  using acad = Autodesk.AutoCAD.ApplicationServices.Application;
  13:  using ACSMCOMPONENTS17Lib;
  14:  using CaddZone.ApplicationServices;
  15:  using Autodesk.AutoCAD.DatabaseServices;
  16:  using Autodesk.AutoCAD.Interop;
  17:   
  18:  namespace AcadBatchProcessing
  19:  {
  20:      public sealed class BatchManager
  21:      {
  22:          FileInfo[] files;
  23:          /// <summary>
  24:          /// Набор файлов, подлежащих пакетной обработке
  25:          /// </summary>
  26:          public FileInfo[] Files
  27:          {
  28:              get { return files; }
  29:              set { files = value; }
  30:          }
  31:   
  32:          IDwgOperation[] operations;
  33:          /// <summary>
  34:          /// Набор операций, которым должны подвергнуться обрабатываемые файлы
  35:          /// </summary>
  36:          public IDwgOperation[] Operations
  37:          {
  38:              get { return operations; }
  39:              set { operations = value; }
  40:          }
  41:   
  42:          XElement journal;
  43:          /// <summary>
  44:          /// Журнал, содержащий информацию из log-файлов, а так же сообщения об ошибках, отловленные на программном уровне.
  45:          /// </summary>
  46:          public XElement Journal
  47:          {
  48:              get { return journal; }
  49:              set { journal = value; }
  50:          }
  51:   
  52:          /// <summary>
  53:          /// Менеджер пакетной обработки файлов
  54:          /// </summary>
  55:          /// <param name="files">Набор файлов, подлежащих пакетной обработке</param>
  56:          /// <param name="operations">Набор операций, которым должны подвергнуться обрабатываемые файлы</param>
  57:          public BatchManager(FileInfo[] files, IDwgOperation[] operations)
  58:          {
  59:              Journal = new XElement("Journal", new XAttribute("Date", DateTime.Now), new XAttribute("User", Environment.UserName));
  60:              Files = files;
  61:              Operations = operations;
  62:          }
  63:   
  64:          /// <summary>
  65:          /// Запуск пакетной обработки файлов
  66:          /// </summary>
  67:          public void Run()
  68:          {
  69:              acad.MainWindow.Visible = false;
  70:              //Создаём новый журнал
  71:              Journal = new XElement("Journal", new XAttribute("Date", DateTime.Now), new XAttribute("User", Environment.UserName));
  72:   
  73:              //Запоминаю документ, который был активным до запуска пакетной обработки, чтобы вновь установить его активным
  74:              //после завершения полной обработки данных
  75:              Document cdoc = acad.DocumentManager.MdiActiveDocument;
  76:   
  77:              //В цикле проходим по всем файлам чертежей
  78:              foreach (FileInfo file in Files)
  79:              {
  80:                  //Открываем чертёж
  81:                  Document dwg = acad.DocumentManager.Open(file.FullName, false);
  82:   
  83:                      //На время отладки пусть окно документа будет видимым...
  84:                      dwg.Window.Visible = true;
  85:   
  86:                      //Активизирую обрабатываемый документ. Проверка обязательна!
  87:                      if (acad.DocumentManager.MdiActiveDocument != dwg)
  88:                      {
  89:                          acad.DocumentManager.MdiActiveDocument = dwg;
  90:                      }                    
  91:   
  92:                      //Создаём xml-элемент, содержащий информацию об обрабатываемом файле
  93:                      XElement xfile = new XElement("Drawing", new XAttribute("Name", file.FullName));
  94:   
  95:                      //Над обрабатываемым файлом вызываем все операции, указанные в свойстве Operations
  96:                      foreach (IDwgOperation operation in Operations)
  97:                      {
  98:                          //Создаём xml-элемент, содержащий информацию о запускаемой операции
  99:                          XElement xop = new XElement("Operation", new XAttribute("Name", operation.OperationName), new XAttribute("Date", DateTime.Now),
 100:                              new XAttribute("Description", operation.Description));
 101:   
 102:                          //Для каждой операции создаём две дочерние подветви:
 103:                          //1.Лог консольного вывода AutoCAD
 104:                          XElement acadCmdLog = new XElement("AcadCommandLog");
 105:   
 106:                          //2.Лог программно отловленных ошибок
 107:                          XElement xErrorsLog = new XElement("ErrorLog");
 108:   
 109:                          xop.Add(acadCmdLog);
 110:                          xop.Add(xErrorsLog);
 111:                          xfile.Add(xop);
 112:   
 113:                          //Указываю, над каким файлом следует выполнить текущую операцию
 114:                          operation.Drawing = dwg;
 115:                          
 116:                          //Стартую запись лога...
 117:                          ((AcadDocument)dwg.AcadDocument).SendCommand("_logFileOn ");
 118:                          string logFileName = string.Empty;
 119:                          try
 120:                          {                            
 121:                              //Запускаю операцию на выполнение...
 122:                              operation.Run();
 123:   
 124:                              //Имитирую нажатие клавиши Escape на тот случай, если скрипт "кривой" и выполнение команды не завершено.
 125:                              //((AcadDocument)dwg.AcadDocument).SendCommand("\0x1b\0x1b ");
 126:                              ((AcadDocument)dwg.AcadDocument).SendCommand("_logFileOff ");//Завершаю запись лога
 127:                              //Получаю имя log-файла, в котором содержится лог консольного вывода AutoCAD
 128:                              logFileName = (string)acad.GetSystemVariable("LOGFILENAME");                           
 129:                          }
 130:                          catch (System.Exception ex)
 131:                          {
 132:                              XElement error = new XElement("Error", new XAttribute("Date", DateTime.Now), ex.Message);
 133:                              xErrorsLog.Add(error);
 134:                              ((AcadDocument)dwg.AcadDocument).SendCommand("_logFileOff ");//Завершаю запись лога
 135:   
 136:                              //Закрываю файл без сохранения произведённых изменений
 137:                              dwg.CloseAndDiscard();
 138:                          }                      
 139:                          //Считываю информацию из log-файла
 140:                          FileInfo logFile = new FileInfo(logFileName);
 141:                          string log = string.Empty;
 142:                          if (logFile.Exists)
 143:                          {
 144:                              using (StreamReader sr = logFile.OpenText())
 145:                              {
 146:                                  log = sr.ReadToEnd();
 147:                                  sr.Close();
 148:                              }
 149:                              //Удаляю log-файл
 150:                              logFile.Delete();
 151:                          }
 152:   
 153:                          //Добавляю в журнал информацию, извлечённую из log-файла
 154:                          acadCmdLog.Add(log);
 155:                          //Добавляю в журнал запись о выполненной операции
 156:                          xfile.Add(xop);
 157:                      }
 158:                      //Сохраняю и закрываю чертёж, над которым выполнялся пакет операций
 159:                      ((AcadDocument)dwg.AcadDocument).Save();
 160:   
 161:                      if (acad.DocumentManager.MdiActiveDocument != cdoc)
 162:                      {
 163:                          acad.DocumentManager.MdiActiveDocument = cdoc;
 164:                      }
 165:   
 166:                      ((AcadDocument)dwg.AcadDocument).Close();
 167:                      //Добавляю в журнал запись об обработанном файле
 168:                      Journal.Add(xfile);
 169:                      acad.MainWindow.Visible = true;
 170:              }
 171:          }
 172:      }
 173:  }

5. Класс операции RunScriptFiles:

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Linq;
   4:  using System.Text;
   5:  using acad = Autodesk.AutoCAD.ApplicationServices.Application;
   6:  using Autodesk.AutoCAD.ApplicationServices;
   7:  using Autodesk.AutoCAD.EditorInput;
   8:  using Autodesk.AutoCAD.DatabaseServices;
   9:  using System.IO;
  10:  using System.Xml.Linq;
  11:  using CaddZone.ApplicationServices;
  12:  using Autodesk.AutoCAD.Interop;
  13:   
  14:  namespace AcadBatchProcessing
  15:  {
  16:      /// <summary>
  17:      /// Модуль, запускающий набор скриптов, упакованных в scr-файлы. Полные имена файлов передаются в качестве параметра 
  18:      /// в конструктор класса.
  19:      /// </summary>
  20:      public sealed class RunScriptFiles : DwgOperation
  21:      {
  22:          /// <summary>
  23:          /// Конструктор класса
  24:          /// </summary>
  25:          /// <param name="parametres">Набор строк, указывающих на xml-файлы, в которых сгруппированы полные имена scr-файлов, которые необходимо выполнить</param>
  26:          public RunScriptFiles(object[] parametres)
  27:              : base(parametres)
  28:          {
  29:              OperationName = "Запуск сценариев (скриптов) в AutoCAD";
  30:              Description = "Запуск сценариев (скриптов) AutoCAD. Сценарии сохраннены в различных scr-файлах. В передаваемых xml-файлах указаны перечни scr-файлов, которые следует запускать.";
  31:          }
  32:   
  33:          /// <summary>
  34:          /// Запуск обработки указанного файла указанным набором скриптов
  35:          /// </summary>
  36:          public override void Run()
  37:          {
  38:              //Анализируем каждый xml-файл
  39:              foreach (object item in Parameters)
  40:              {
  41:                  FileInfo file = new FileInfo((string)item);
  42:                  if (!file.Exists) throw new FileNotFoundException("Не удалось найти файл ", file.FullName);
  43:                  if (file.Extension.Replace(".", string.Empty) != "xml") throw new FormatException("Указанный файл должен иметь расширение XML");
  44:                  
  45:                  //Вызываем на исполнение каждый сценарий (скрипт), указанный в xml-файле операции.
  46:                  foreach (string scrFile in XElement.Load(file.FullName).Elements("Script").Where(n => Boolean.Parse(n.Attribute("Run").Value) == true).Select(n => n.Attribute("File").Value))
  47:                  {
  48:                      //Запоминаю значение системной переменной
  49:                      object filedia = acad.GetSystemVariable("FILEDIA");
  50:   
  51:                      //Устанавливаю нужное мне значение
  52:                      acad.SetSystemVariable("FILEDIA", 0);
  53:   
  54:                      //Синхронный вариант вызова скрипта
  55:                      ((AcadDocument) Drawing.AcadDocument).SendCommand(string.Format("_script {0}\n", scrFile));
  56:   
  57:                      //Возвращаю системной переменной исходное состояние
  58:                      acad.SetSystemVariable("FILEDIA", filedia);
  59:                  }            
  60:              }
  61:          }
  62:      }
  63:  }


Теперь пишу примеры, демонстрирующие работу библиотеки:

   1:  using Autodesk.AutoCAD.ApplicationServices;
   2:  using Autodesk.AutoCAD.EditorInput;
   3:  using Autodesk.AutoCAD.Runtime;
   4:  using Autodesk.AutoCAD.Windows;
   5:  using acApp = Autodesk.AutoCAD.ApplicationServices;
   6:  using ACSMCOMPONENTS17Lib;
   7:  using System.Windows.Forms;
   8:  using System;
   9:  using System.Linq;
  10:  using System.Collections.Generic;
  11:  using System.IO;
  12:  using Autodesk.AutoCAD.Interop;
  13:   
  14:  namespace AcadBatchProcessing
  15:  {
  16:      public class TestCommands
  17:      {
  18:          Editor ed = acApp.Application.DocumentManager.MdiActiveDocument.Editor;
  19:          string dirName = @"E:\000\АВ_Пролетное строение";
  20:          string sheetSetName = @"E:\000\АВ_Пролетное строение\ав_пролетное строение.dst";
  21:   
  22:          //Тестовая команда получения всех чертежей из определённого каталога, без поиска по подкаталогам
  23:          [CommandMethod("q1")]
  24:          public void q1()
  25:          {
  26:              DrawingSearcher mng = new DrawingSearcher();
  27:              foreach (FileInfo file in mng.GetDrawingsFromDirectory(dirName, false))
  28:              {
  29:                  ed.WriteMessage(Environment.NewLine + file.FullName);
  30:              }
  31:          }
  32:   
  33:          //Тестовая команда получения всех чертежей из определённого каталога, с рекурсивным поиском по всем подкаталогам
  34:          [CommandMethod("q2")]
  35:          public void q2()
  36:          {
  37:              DrawingSearcher mng = new DrawingSearcher();
  38:              foreach (FileInfo file in mng.GetDrawingsFromDirectory(dirName, true))
  39:              {
  40:                  ed.WriteMessage(Environment.NewLine + file.FullName);
  41:              }
  42:          }
  43:   
  44:          ////Тестовая команда получения всех чертежей из определённой подшивки
  45:          [CommandMethod("q3")]
  46:          public void q3()
  47:          {
  48:              DrawingSearcher mng = new DrawingSearcher();
  49:              foreach (FileInfo file in mng.GetSheetSetDrawings(sheetSetName))
  50:              {
  51:                  ed.WriteMessage(Environment.NewLine + file.FullName);
  52:              }
  53:          }
  54:   
  55:          //Тестовая команда запуска пакетной обрабоки файлов (проверяю пока на одном файле чертежа, используя один файл скрипта).
  56:          [CommandMethod("q4", CommandFlags.Session)]
  57:          public void q4()
  58:          {
  59:              //Формирую список файлов, которые следует обработать нужными скриптами
  60:              FileInfo[] files = new FileInfo[1] { new FileInfo(@"C:\Documents and Settings\andrey.bushman\Мои документы\Drawing1++.dwg") };
  61:   
  62:              //Формирую список xml-файлов, содержащие имена scr-файлов которые необходимо запустить для каждого чертежа из списка files
  63:              RunScriptFiles[] op = new RunScriptFiles[1] { new RunScriptFiles(new object[1] { @"I:\Visual Studio 2010\Projects\AcadBatchProcessing\AcadBatchProcessing\Чистка файла и изменение коэф. сжатия шрифта.xml" }) };
  64:   
  65:              //Создаю экземпляр менеджера пакетной обработки
  66:              BatchManager mng = new BatchManager(files, op);
  67:   
  68:              //Запускаю пакетную обработку файлов
  69:              mng.Run();            
  70:          }
  71:      }
  72:  }

В коде команды, именованной как "q4" указывается имя некоторого xml-файла, в котором хранится информация о том, какие сценарии следует запускать. Вот содержимое этого файла:

   1:  <?xml version="1.0" encoding="utf-8" ?> 
   2:  <!--Разработчик: Hwd -->
   3:  <!--Пакет скриптов, выполняющих чистку чертежа от мусора + изменяют коэффициент сжатия шрифта "Тип А курсив" на 0,8.-->
   4:  <!--Атрибуты Library и Class содержат информацию о том, под какой класс, реализующий IDwgOperation писался данный XML-файл-->
   5:  <Scripts Library="AcadBatchProcessing" Class="RunScriptFiles" >
   6:    <Script Name="CreateCircle" File="E:\000\circle.scr" Description="Чистка файла" Run="True"/>
   7:    <Script Name="Clear" File="E:\000\Чистка.scr" Description="Чистка файла" Run="False"/>
   8:    <Script Name="ChangeCoeffWidth" File="E:\000\Установка для Типа А курсива коэф. сжатия в 0,8.scr" Description="Чистка файла" Run="False"/>
   9:  </Scripts>

Аналогично тому примеру, который я написал применительно к пакетной обработки файлов скриптами, можно написать любую другую логику обработки файлов, реализовав интерфейс IDwgOperation.

Исходники в формате MS Visual Studio 2010 здесь.

Откомпилированные версии библиотеки (.Net 3.5 SP1 для AutoCAD 2009):

Comments