Фатальная ошибка при динамическом копировании/стирании блоков

Автор Тема: Фатальная ошибка при динамическом копировании/стирании блоков  (Прочитано 5327 раз)

0 Пользователей и 1 Гость просматривают эту тему.

Тема содержит сообщение с Решением. Нажмите здесь чтобы посмотреть его.

Оффлайн Александр Пекшев aka ModisАвтор темы

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
Всем привет. Давно не заходил - все как-то некогда(
Есть у меня в одной функции "косяк", который приводит к фатальной ошибке. Тема чем-то схожа с моей другой темой, но тот ответ не подходит)
В общем - суть функции в том, что при использовании DrawJig происходит копирование выбранных объектов. Временное копирование. Как работает функция можно увидеть в этом видео, дабы долго не объяснять
И все бы хорошо, но вот при работе с блоками (и только с ними) происходит фатальная ошибка. С блоками вообще всегда сложнее))
Мой уровень знаний не позволяет мне найти решение, поэтому обращаюсь к вам (особенно к Александру Ривилису и его мастерству с ходу предлагать верное решение ;) )
Думаю, весь код функции не нужен и достаточно только самого DrawJig:
Извините, вам запрещён просмотр содержимого спойлеров.

Буду рад любым вариантам решения

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Александр Пекшев aka Modis
Тяжело искать черную кошку в тёмной комнате. Особенно если её там нет!
Это намёк на то, что причина фатала не в этом коде.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Александр Пекшев aka ModisАвтор темы

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
Это намёк на то, что причина фатала не в этом коде
Как скажите! ;)
Код - C# [Выбрать]
  1. // Разметить
  2. private void Mark(double distance, ObjectId[] idArray)
  3. {
  4.     var doc = AcApp.DocumentManager.MdiActiveDocument;
  5.     var db = doc.Database;
  6.     var ed = doc.Editor;
  7.  
  8.     try
  9.     {
  10.         // Используем транзикцию
  11.         var tr = doc.TransactionManager.StartTransaction();
  12.         using (tr)
  13.         {
  14.             //var btr = (BlockTableRecord) tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite, false);
  15.             var ppo = new PromptPointOptions(string.Empty);
  16.             ppo.Keywords.Add("Примитив");
  17.             var kws = ppo.Keywords.GetDisplayString(true);
  18.             ppo.Message = "\nУкажите базовую точку или: " + kws;
  19.             ppo.AllowNone = true;
  20.             var ppr = ed.GetPoint(ppo);
  21.             if (ppr.Status == PromptStatus.Keyword)
  22.             {
  23.                 if (ppr.StringResult.Equals("Примитив"))
  24.                 {
  25.                     MarkByObject(distance, idArray);
  26.                     tr.Commit();
  27.                     return;
  28.                 }
  29.             }
  30.             if (ppr.Status != PromptStatus.OK)
  31.             {
  32.                 return;
  33.             }
  34.             var jig = new MpMultiCopyMarkJig();
  35.             var rs = jig.StartJig(
  36.                 ppr.Value,
  37.                 distance,
  38.                 idArray
  39.                 );
  40.             if (rs.Status != PromptStatus.OK) return;
  41.             var pts = jig.PointCollection(); //Все точки
  42.             pts.RemoveAt(0); // удаляем самую первую точку
  43.             foreach (Point3d pt in pts)
  44.             {
  45.                 foreach (var objId in idArray)
  46.                 {
  47.                     //var en = (Entity) objId.GetObject(OpenMode.ForWrite).Clone();
  48.                     var coll = new ObjectIdCollection { objId };
  49.                     var mapping = new IdMapping();
  50.                     db.DeepCloneObjects(coll, db.CurrentSpaceId, mapping, false);
  51.                     var pair = mapping[objId];
  52.                     var en = tr.GetObject(pair.Value, OpenMode.ForWrite) as Entity;
  53.  
  54.                     var from = MpCadHelpers.UcsToWcs(ppr.Value);
  55.                     var to = pt;
  56.                     var vec = to - from;
  57.                     var mat = Matrix3d.Displacement(vec);
  58.                     en?.TransformBy(mat);
  59.                     //btr.AppendEntity(en);
  60.                     //tr.AddNewlyCreatedDBObject(en, true);
  61.                 }
  62.             }
  63.             tr.Commit();
  64.         }
  65.     } // try
  66.     catch (System.Exception ex)
  67.     {
  68.         MpExWin.Show(ex);
  69.     }
  70. }

Отмечено как Решение Александр Пекшев aka Modis 07-06-2016, 21:38:01

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Ну как минимум я увидел утечку памяти. Ты клонируешь объекты в WorldDraw, но никогда не освобождаешь их память. Так как WorldDraw вызывается очень часто (у тебя зачем-то в CursorHasMoved возвращается true при расстоянии больше 1e-16, хотя достаточно было бы 1e-2 или 1e-3 для обычных чертежей), то жуткая утечка памяти приводит к фаталам. Для блоков это особенно актуально.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Еще обратил внимание, что в WorldDraw ты открываешь исходный(ые) примитивы ForWrite. Зачем? Модифицируешь ты не их, а их клоны. Я бы там вообще убрал транзакцию и использовал бы ObjectId.Open(ForRead)
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Александр Пекшев aka ModisАвтор темы

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
Александр Ривилис, скажите, если я заменю это
Код - C# [Выбрать]
  1. var en = (Entity)objId.GetObject(OpenMode.ForWrite).Clone();
на это
Код - C# [Выбрать]
  1. usung(var en = (Entity)objId.GetObject(OpenMode.ForRead).Clone())
  2. {
  3. }
Это будет правильно? На сколько я помню, при этом срабатывает en.Dispose()

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Да. Но нужно проверить в этом контексте. И лучше без транзакции.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Александр Пекшев aka ModisАвтор темы

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
Но нужно проверить в этом контексте
Конечно! Сегодня вечером буду пробовать и тестировать

Оффлайн Александр Пекшев aka ModisАвтор темы

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
Внес все изменения о которых говорили - вроде ошибка исчезла. Тестировал только на одном блоке. Попросил пользователей проверить, но, думаю, все будет хорошо.
Смело ставлю решение для темы  :)