Сообщество программистов Autodesk в СНГ

ADN Club => AutoCAD .NET API => Тема начата: NomadV от 20-06-2014, 13:35:04

Название: Пакетная обработка чертежей
Отправлено: NomadV от 20-06-2014, 13:35:04
Пишу программу пакетной обработки автокадовских файлов (в основном извлечение из них некоторой информации) для Autocad 2014. При работе с базой данных чертежа без его открытия в окне Autocad проблем нет. Но иногда все же нужно взаимодействие с пользователем (если не удалось найти нужную информацию автоматически). И вот тут получаю постоянные ошибки вида:
Цитировать
FatalExecutionEngineError was detected
Message: В среде выполнения обнаружена критическая ошибка. Ошибка произошла по адресу 0xe62225c0 в потоке 0xacc. Код ошибки 0xc0000005. Она может быть вызвана ошибкой в CLR или в небезопасных либо не поддающихся проверке фрагментах пользовательского кода. Обычно источниками таких ошибок бывают ошибки упаковки, допускаемые пользователями при COM-взаимодействии, либо PInvoke, повредивший стек.
Ниже упрощенный вариант программы:
Код - C# [Выбрать]
  1. // тест пакетной обработки
  2.         [CommandMethod("BTest", CommandFlags.Session)]
  3.         public void BTest()
  4.         {
  5.             System.IO.FileInfo[] files = null;
  6.             System.IO.DirectoryInfo rootDir = new System.IO.DirectoryInfo(@"d:\BTest");
  7.             files = rootDir.GetFiles("*.dwg");
  8.  
  9.             if (files.Length == 0) return;
  10.             foreach (System.IO.FileInfo file in files)
  11.             {
  12.                 // Работа с БД dwg-файла без открытия файла в окне автокада
  13.                 using (Database dwgDB = new Database(false, true))
  14.                 {
  15.                     dwgDB.ReadDwgFile(file.FullName, System.IO.FileShare.ReadWrite, false, "");
  16.                     //Далее манипуляции с базой данных чертежа
  17.                 }
  18.  
  19.                 //Если файл все же понадобилось открыть
  20.                 if (true)
  21.                 {
  22.                     Document activeDoc = Application.DocumentManager.MdiActiveDocument;
  23.                     //Активный файл не должен быть безымянным
  24.                     if (Convert.ToInt32(Application.GetSystemVariable("dwgtitled")) == 0) return;
  25.                     Document dwgFile = Application.DocumentManager.Open(file.FullName, false);
  26.                     Application.DocumentManager.MdiActiveDocument = dwgFile;
  27.                     if (Application.DocumentManager.MdiActiveDocument != dwgFile) return;
  28.  
  29.                     //Далее запросы пользователю и т.п. в активном документе
  30.                     using (Database dwgDB2 = Application.DocumentManager.MdiActiveDocument.Database)
  31.                     {
  32.                         Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
  33.                         PromptEntityOptions options = new PromptEntityOptions("\nВыберите однострочный текст ");
  34.                         options.SetRejectMessage("\nОшибочный выбор. Это не однострочный текст");
  35.                         options.AddAllowedClass(typeof(DBText), true);
  36.                         PromptEntityResult pEResult = ed.GetEntity(options);
  37.                     }
  38.  
  39.                     Application.DocumentManager.MdiActiveDocument = activeDoc;
  40.                     dwgFile.CloseAndDiscard();
  41.                 }
  42.  
  43.             }
  44.  
  45.         }
Название: Re: Пакетная обработка чертежей
Отправлено: Александр Ривилис от 20-06-2014, 13:39:02
А это зачем:
Код - C# [Выбрать]
  1. using (Database dwgDB2 = Application.DocumentManager.MdiActiveDocument.Database)
???
Название: Re: Пакетная обработка чертежей
Отправлено: Андрей Бушман от 20-06-2014, 13:50:38
Цитировать
В AutoCAD класс DBObject реализовывает интерфейс IDisposable. Соответственно, указанный интерфейс реализуется и всеми классами, унаследованными от DBObject. Этот же интерфейс реализован и классами Document и Database, однако для Document  вызывать Dispose() никогда не следует (это делает сам AutoCAD), а так же нельзя вызывать Dispose() для объекта, хранящегося в свойстве Document.Database.
тынц (http://bushman-andrey.blogspot.ru/2014/03/autocad-net-api-idisposable.html).
Название: Re: Пакетная обработка чертежей
Отправлено: NomadV от 20-06-2014, 18:13:15
Database для теста пожалуй что и совсем ни к чему. Тем более в конструкции using.
Андрей, спасибо, что ткнули носом в статью. Оба Ваших сайта читал с интересом и ее вроде просматривал, но вот не отложилось. Тогда про IDisposable не задумывался.
Только вот все равно что-то не так. Я уж разные варианты пробовал. С using - это уж изголяться начал. И, как оказалось, наоборот усугубил.
Ну вот меняю например фрагмент с открытием файла на такой:
Код - C# [Выбрать]
  1. //Если файл все же понадобилось открыть
  2.                 if (true)
  3.                 {
  4.                     Document activeDoc = Application.DocumentManager.MdiActiveDocument;
  5.                     //Активный файл не должен быть безымянным
  6.                     if (Convert.ToInt32(Application.GetSystemVariable("dwgtitled")) == 0) return;
  7.                     Document dwgFile = Application.DocumentManager.Open(file.FullName, false);
  8.                     Application.DocumentManager.MdiActiveDocument = dwgFile;
  9.                     if (Application.DocumentManager.MdiActiveDocument != dwgFile) return;
  10.  
  11.                     //Далее запросы пользователю и т.п. в активном документе
  12.                     Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
  13.                     PromptEntityOptions options = new PromptEntityOptions("\nВыберите однострочный текст ");
  14.                     options.SetRejectMessage("\nОшибочный выбор. Это не однострочный текст");
  15.                     options.AddAllowedClass(typeof(DBText), true);
  16.                     PromptEntityResult pEResult = ed.GetEntity(options);
  17.  
  18.                     Application.DocumentManager.MdiActiveDocument = activeDoc;
  19.                     dwgFile.CloseAndDiscard();
  20.                 }
И на втором-третьем файле опять получаю:
Цитировать
FatalExecutionEngineError was detected
Message: В среде выполнения обнаружена критическая ошибка. Ошибка произошла по адресу 0xe6e7175e в потоке 0x217c. Код ошибки 0xc0000005. Она может быть вызвана ошибкой в CLR или в небезопасных либо не поддающихся проверке фрагментах пользовательского кода. Обычно источниками таких ошибок бывают ошибки упаковки, допускаемые пользователями при COM-взаимодействии, либо PInvoke, повредивший стек.
Вроде как в строке:
Код - C# [Выбрать]
  1. PromptEntityResult pEResult = ed.GetEntity(options);
Даже ткнуть в текст не успеваю. Запрос, потом ошибка.
С другой стороны, если без отладки запускать, то вроде работает.
Название: Re: Пакетная обработка чертежей
Отправлено: Александр Ривилис от 20-06-2014, 18:24:31
Давай, чтобы можно было проверить не кусок кода, а полностью тестовый пример.
P.S.: И используй пожалуйста для кода на C# тэги [code=csharp]...код программы...[/code]- я уже не первый раз исправляю, чтобы читать было легче.
Название: Re: Пакетная обработка чертежей
Отправлено: Александр Ривилис от 20-06-2014, 18:26:19
P.S.S.: Стесняюсь спросить какое значение системной переменной FIBERWORLD?
Название: Re: Пакетная обработка чертежей
Отправлено: NomadV от 20-06-2014, 19:01:04
Про теги на будущее учту.
Программа целиком:
Код - C# [Выбрать]
  1. // тест пакетной обработки
  2.         [CommandMethod("BTest", CommandFlags.Session)]
  3.         public void BTest()
  4.         {
  5.             System.IO.FileInfo[] files = null;
  6.             System.IO.DirectoryInfo rootDir = new System.IO.DirectoryInfo(@"d:\BTest");
  7.             files = rootDir.GetFiles("*.dwg");
  8.  
  9.             if (files.Length == 0) return;
  10.             foreach (System.IO.FileInfo file in files)
  11.             {
  12.                 // Работа с БД dwg-файла без открытия файла в окне автокада
  13.                 using (Database dwgDB = new Database(false, true))
  14.                 {
  15.                     dwgDB.ReadDwgFile(file.FullName, System.IO.FileShare.ReadWrite, false, "");
  16.                     //Далее манипуляции с базой данных чертежа
  17.                 }
  18.  
  19.                 //Если файл все же понадобилось открыть
  20.                 if (true)
  21.                 {
  22.                     Document activeDoc = Application.DocumentManager.MdiActiveDocument;
  23.                     //Активный файл не должен быть безымянным
  24.                     if (Convert.ToInt32(Application.GetSystemVariable("dwgtitled")) == 0) return;
  25.                     Document dwgFile = Application.DocumentManager.Open(file.FullName, false);
  26.                     Application.DocumentManager.MdiActiveDocument = dwgFile;
  27.                     if (Application.DocumentManager.MdiActiveDocument != dwgFile) return;
  28.  
  29.                     //Далее запросы пользователю и т.п. в активном документе
  30.                     Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
  31.                     PromptEntityOptions options = new PromptEntityOptions("\nВыберите однострочный текст ");
  32.                     options.SetRejectMessage("\nОшибочный выбор. Это не однострочный текст");
  33.                     options.AddAllowedClass(typeof(DBText), true);
  34.                     PromptEntityResult pEResult = ed.GetEntity(options);
  35.  
  36.                     Application.DocumentManager.MdiActiveDocument = activeDoc;
  37.                     dwgFile.CloseAndDiscard();
  38.                 }
  39.  
  40.             }
  41.  
  42.         }

FIBERWORLD=1. А надо 0? Я думал от этого только с пользовательскими формами проблемы могут быть. Честно говоря, вообще не знаю ничего про эту технологию, но обязательно почитаю.
Поставил NEXTFIBERWORLD=0 и после открытия первого же файла ничего больше не происходит. Я опять туплю?)
Название: Re: Пакетная обработка чертежей
Отправлено: Александр Ривилис от 20-06-2014, 19:28:02
FIBERWORLD=1. А надо 0?
Для нормальной работы должна быть 1, для отладки форм и не только - 0. Но это может приводить к тому что вообще не будут открываться dwg-файлы через Application.DocumentManager.Open
Так что тут нужно экспериментировать.
P.S.: Проверил - похоже это проблема отладчика, так как без отладки всё работает нормально. Единственно что обратил внимание, что ты не выполняешь блокировку документа, что неправильно даже если ты его явно не меняешь.
Так что код должен выглядеть так:
Код - C# [Выбрать]
  1.     [CommandMethod("BTest", CommandFlags.Session)]
  2.     public void BTest()
  3.     {
  4.       System.IO.FileInfo[] files = null;
  5.       System.IO.DirectoryInfo rootDir = new System.IO.DirectoryInfo(@"d:\BTest");
  6.       files = rootDir.GetFiles("*.dwg");
  7.  
  8.       if (files.Length == 0) return;
  9.       foreach (System.IO.FileInfo file in files) {
  10.         // Работа с БД dwg-файла без открытия файла в окне автокада
  11.         using (Database dwgDB = new Database(false, true)) {
  12.           dwgDB.ReadDwgFile(file.FullName, System.IO.FileShare.ReadWrite, false, "");
  13.           //Далее манипуляции с базой данных чертежа
  14.         }
  15.  
  16.         // Если файл все же понадобилось открыть
  17.         if (true) {
  18.           Document activeDoc = Application.DocumentManager.MdiActiveDocument;
  19.           //Активный файл не должен быть безымянным
  20.           if (Convert.ToInt32(Application.GetSystemVariable("dwgtitled")) == 0) return;
  21.           Document dwgFile = Application.DocumentManager.Open(file.FullName, false);
  22.           Application.DocumentManager.MdiActiveDocument = dwgFile;
  23.           if (Application.DocumentManager.MdiActiveDocument != dwgFile) return;
  24.           using (DocumentLock doclock = dwgFile.LockDocument()) {
  25.             //Далее запросы пользователю и т.п. в активном документе
  26.             Editor ed = dwgFile.Editor;
  27.             PromptEntityOptions options = new PromptEntityOptions("\nВыберите однострочный текст ");
  28.             options.SetRejectMessage("\nОшибочный выбор. Это не однострочный текст");
  29.             options.AddAllowedClass(typeof(DBText), true);
  30.             PromptEntityResult pEResult = ed.GetEntity(options);
  31.             if (pEResult.Status == PromptStatus.OK) {
  32.               ed.WriteMessage("\nOK!");
  33.             }
  34.           }
  35.           Application.DocumentManager.MdiActiveDocument = activeDoc;
  36.           dwgFile.CloseAndDiscard();
  37.         }
  38.       }
  39.     }
  40.  
Название: Re: Пакетная обработка чертежей
Отправлено: Андрей Бушман от 20-06-2014, 21:32:22
Александр Ривилис,
Раз уж Session, то не плохо было бы блокировать документ при работе с ним.
Название: Re: Пакетная обработка чертежей
Отправлено: Александр Ривилис от 20-06-2014, 21:34:54
Александр Ривилис,
Раз уж Session, то не плохо было бы блокировать документ при работе с ним.
Андрей. Посмотри (внимательно) мой код и комментарий.
Название: Re: Пакетная обработка чертежей
Отправлено: Андрей Бушман от 20-06-2014, 21:38:58
Александр Ривилис,
Раз уж Session, то не плохо было бы блокировать документ при работе с ним.
Андрей. Посмотри (внимательно) мой код и комментарий.

Да, проморгал 24-ю строчку :)
Название: Re: Пакетная обработка чертежей
Отправлено: NomadV от 25-06-2014, 12:48:30
Кстати, похоже CommandFlags.Session тут имеет принципиальное значение, да? Если ставлю Modal, то открывается первый файл и на этом все заканчивается.
Название: Re: Пакетная обработка чертежей
Отправлено: Александр Ривилис от 25-06-2014, 13:00:36
Кстати, похоже CommandFlags.Session тут имеет принципиальное значение, да? Если ставлю Modal, то открывается первый файл и на этом все заканчивается.
Конечно. И именно так и должно быть. В этом случае не работают операции переключения между документами. Точнее операция переключения дожидается завершения конца модальной команды.