Document.Editor.Command(...) и т.п. = eInvalidInput на AutoCAD 2016

Автор Тема: Document.Editor.Command(...) и т.п. = eInvalidInput на AutoCAD 2016  (Прочитано 15787 раз)

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

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

Оффлайн A77X7Автор темы

  • ADN OPEN
  • Сообщений: 20
  • Карма: 0
Добрый день!
Суть проекта - выполнение исходного кода на C# в AutoCAD (динамическая компиляция и всё такое...).
Есть сборка на C# с классом от IExtensionApplication. Грузится в AutoCAD при его запуске (через реестр).
В ней в Initialize и DocumentManager_DocumentCreated подписываемся на нужные события. Здесь ничего особенного...
В итоге имеем обработчики событий типа
 
Код - C# [Выбрать]
  1. doc.CommandEnded += Doc_CommandEnded;

В таких обработчиках код типа:
Код - C# [Выбрать]
  1. compile_and_load_module(ctx);
В ctx всякие параметры для компиляции - пути к исходникам, пути к ссылкам, тип, запускаемый метод и т.п.
 
compile_and_load_module выполняет компиляцию исходников (CSharpCodeProvider.CompileAssemblyFromFile), сохраняет сборку на диске, загружает её в текущий AppDomain (т.е. в AutoCAD), ищет тип (из ctx) и выполняет метод (из ctx).
Скомпилированный метод делает какую-либо полезную работу, например вызывает другие команды AutoCAD...
Код - C# [Выбрать]
  1. var dm = Application.DocumentManager;
  2. var doc = dm.MdiActiveDocument;
  3. var ed = doc.Editor;
  4. ctx.acad_dwg.Editor.WriteMessage("Перед Editor.Command() 5 ...");
  5. await dm.ExecuteInCommandContextAsync(async (obj) =>
  6.   {
  7.     ed.WriteMessage("10000000000000000...");
  8.     ed.Command("_ATTSYNC", "_N", n);
  9.     ed.WriteMessage("20000000000000000...");
  10.   },
  11.   null
  12. );
Вызов команды я пытался сделать и как await ed.CommandAsync и через ExecuteInCommandContextAsync и без неё.
Читал http://through-the-interface.typepad.com/through_the_interface/2014/03/autocad-2015-calling-commands.html и http://through-the-interface.typepad.com/through_the_interface/2015/03/autocad-2016-calling-commands-from-autocad-events-using-net.html и много чего ещё.
Там написано, что так всё должно работать и работает, но у меня не работает. Возможно это из-за более длинной цепочки компиляции, загрузки, выполнения и т.п. Раньше это всё у меня работало через acedCmd...
Может кто-нибудь подскажет куда копать?..
« Последнее редактирование: 21-01-2016, 15:53:47 от A77X7 »

Оффлайн Андрей Бушман

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
В чём соль сего действа?

Оффлайн A77X7Автор темы

  • ADN OPEN
  • Сообщений: 20
  • Карма: 0
Оперативное изменение поведения модуля (AutoCADа). Т.е. если исходник изменится, то он перекомпилируется и выполнится новая его версия.
(Исходник берётся из сети, централизовано)

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

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
1. Начни с того, что отформатируй код по правилам форума (смотри у меня в подписи).
2. Это касается только команды _ATTSYNC или каких-то еще?
3. Почему вместо ed.Command не воспользоваться Document.SendStringToExecute? Синхронности ты всё-равно не добьешься.
Вообще запуск команды из обработчика события - это "жуткая жуть".
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

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

Оффлайн Андрей Бушман

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Т.е. если исходник изменится, то он перекомпилируется и выполнится новая его версия.
Напоминает игру в бадминтон в кукурузе. "Новая версия", говоришь... Но у тебя в рамках этой сессии в твой AppDomain уже загружена предыдущая версия твоей сборки. Это если бы в AutoCAD можно было бы использовать несколько AppDomain вместо одного общего - тогда да, а так то, что ты пытаешься прикрутить - достаточно сомнительная "конструкция" (имхо).

Оффлайн A77X7Автор темы

  • ADN OPEN
  • Сообщений: 20
  • Карма: 0
Да, я с начала сам сомневался, но по факту всё работает именно так. Выполняется последняя загруженная версия.
Это работает уже около 2-х лет как часы. И не только в среде AutoCAD.
Проблема не в этом...

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

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
A77X7
Повторюсь:
1. Начни с того, что отформатируй код по правилам форума (смотри у меня в подписи).
Ну и на остальные мои вопросы ты не ответил.
Выполняется последняя загруженная версия.
Многое зависит от простоты кода. Если в этом коде ты подписываешься на какие-то AutoCAD'овские события, то это верный путь к аварийному завершению AutoCAD.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн A77X7Автор темы

  • ADN OPEN
  • Сообщений: 20
  • Карма: 0
1. Начни с того, что отформатируй код по правилам форума (смотри у меня в подписи).
2. Это касается только команды _ATTSYNC или каких-то еще?
3. Почему вместо ed.Command не воспользоваться Document.SendStringToExecute? Синхронности ты всё-равно не добьешься.
Вообще запуск команды из обработчика события - это "жуткая жуть".
1.сейчас...
2.ну пробовал _REGENALL, например, и ещё какие-то свои и встроенные (для отладки), результат один: или eInvalidInput или тишина.
3.собственно синхронность то и нужна и вроде как пишут, что можно этого добиться. Document.SendStringToExecute... ну это только как запасной выход, и то может и не получится то, что задумано

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

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
3.собственно синхронность то и нужна и вроде как пишут, что можно этого добиться.
Очень сильно сомневаюсь. Для синхронности я бы организовал в коде команду (модальную), которую запускал бы из обработчика при помощи  Document.SendStringToExecute, а внутри этой команды попробовал запускать команды уже синхронно.

В любом случае если ты уперся в стену и без помощи Autodesk ты не можешь решить эту задачу, тебе придётся сделать минимальный тестовый проект, который я проверю и если не найду решения, то отправляю в ADN DevHelp.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн A77X7Автор темы

  • ADN OPEN
  • Сообщений: 20
  • Карма: 0
Многое зависит от простоты кода. Если в этом коде ты подписываешься на какие-то AutoCAD'овские события, то это верный путь к аварийному завершению AutoCAD.
События не трогаю, по крайней мере пока. В коде делаю модификацию вхождений блоков. И это всё работало нормально, до тех пор пока не потребовалось вызывать команды в 2016ом.

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

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

Оффлайн A77X7Автор темы

  • ADN OPEN
  • Сообщений: 20
  • Карма: 0
А в 2015-ом?
У нас только 2016й и 2014й (там через acedCmd работает)

Оффлайн A77X7Автор темы

  • ADN OPEN
  • Сообщений: 20
  • Карма: 0
А наличие установленного ServicePack для 2016?
Конкретно сейчас проверяю на AutoCAD 2016 MEP SP1

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

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

Оффлайн A77X7Автор темы

  • ADN OPEN
  • Сообщений: 20
  • Карма: 0
А acedCmdS вместо acedCmd в 2016?
Ээээ... уже запутался... кажется это кончилось тем, что я не нашёл её определение, чтобы его DllImport... Хотя нет, вот же в документации ARX... сейчас попробую (возможно ещё раз)

Оффлайн A77X7Автор темы

  • ADN OPEN
  • Сообщений: 20
  • Карма: 0
Сделал так:
Код - C# [Выбрать]
  1.         [System.Security.SuppressUnmanagedCodeSecurity]
  2.         [DllImport(@"accore.dll", CallingConvention = CallingConvention.Cdecl)]
  3.         extern static int acedCmdS(IntPtr resbuf, bool stub1, IntPtr stub2);
...
Код - C# [Выбрать]
  1.         ResultBuffer rb = new ResultBuffer();
  2.         rb.Add(new TypedValue(5005, "_ATTSYNC"));
  3.         rb.Add(new TypedValue(5005, "_N"));
  4.         rb.Add(new TypedValue(5005, n));
  5.         int stat = acedCmdS(rb.UnmanagedObject, false, IntPtr.Zero);
  6.  
  7.         log("stat=" + stat.ToString() + "\r\n");
До последней строки (где log()) не доходит, исключений нет, тишина просто

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

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
P.S.: Кстати, интересная мысль. А если для проверки ты вместо того, чтобы что-то там компилировать, сохранять, загружать и выполнять - просто запустишь команду из обработчика CommandEnded через DocumentManager.ExecuteInCommandContextAsync, то команда отработает?
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн A77X7Автор темы

  • ADN OPEN
  • Сообщений: 20
  • Карма: 0
Извиняюсь. У меня паника уже... acedCmdS выполняется, всё отлично.
Счастье то какое!
Ещё перепроверю пару десятков раз...

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

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
До последней строки (где log()) не доходит, исключений нет, тишина просто

Тут я не понял. Если не доходит, то может ждёт чего-то от пользователя. Установи CMDECHO в 1 чтобы в командной строке что-нибудь печаталось.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн A77X7Автор темы

  • ADN OPEN
  • Сообщений: 20
  • Карма: 0
Тут я не понял. Если не доходит, то может ждёт чего-то от пользователя. Установи CMDECHO в 1 чтобы в командной строке что-нибудь печаталось.
Всё доходит. Я просто новый файлик с исходником из студии не закинул туда где AutoCAD ждёт...
Прошу прощения

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

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Подозреваю, что
Код - C# [Выбрать]
  1. extern static int acedCmdS(IntPtr resbuf, bool stub1, IntPtr stub2);
стоит заменить на
Код - C# [Выбрать]
  1. extern static int acedCmdS(IntPtr resbuf, [MarshalAs(UnmanagedType.U1)] bool stub1, IntPtr stub2);
(читать здесь: https://msdn.microsoft.com/en-us/library/ms182206.aspx)
Причина в разнице типов bool в C++ и C#. Впрочем, так как передаётся false (т.е. 0), то возможно разницы и не будет.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Отмечено как Решение Александр Ривилис 23-01-2016, 15:17:20

Оффлайн A77X7Автор темы

  • ADN OPEN
  • Сообщений: 20
  • Карма: 0
Спасибо за оперативную помощь. Всё теперь работает, проверил и в 2014м и в 2016м.
В итоге получилось вот что:
Код - C# [Выбрать]
  1. #if R17_2 || R18_0 || R18_1 || R18_2
  2.         [System.Security.SuppressUnmanagedCodeSecurity]
  3.         [DllImport(@"acad.exe", CallingConvention = CallingConvention.Cdecl)]
  4.         extern static int acedCmd(IntPtr resbuf);
  5. #elif R19_0 || R19_1
  6.         [System.Security.SuppressUnmanagedCodeSecurity]
  7.         [DllImport(@"accore.dll", CallingConvention = CallingConvention.Cdecl)]
  8.         extern static int acedCmd(IntPtr resbuf);
  9. #elif R20_0 || R20_1
  10.         [System.Security.SuppressUnmanagedCodeSecurity]
  11.         [DllImport(@"accore.dll", CallingConvention = CallingConvention.Cdecl)]
  12.         extern static int acedCmdS(IntPtr resbuf, bool stub1, IntPtr stub2);
  13.         static int acedCmd(IntPtr resbuf)
  14.         {
  15.             return acedCmdS(resbuf, false, IntPtr.Zero);
  16.         }
  17. #endif
  18.  
  19. //...
  20. acedCmd(rb.UnmanagedObject);
  21.  

P.S. По поводу новой версии кода. Да, вы правы, когда речь идёт о том, что мы загружаем (Assembly.Load...) новую версию уже загруженной сборки, если она была где-то скомпилирована. Если же она скомпилирована прямо тут (динамически через CodeProvider), она сразу грузится в AppDomain и изменения вступают в силу.
P.P.S. Не факт, что размер bool == 1 (ибо определяется реализацией), у MS, да == 1. Ну и + там всегда false. Честно говоря, я думал компилятор сам разберётся.

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

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Я бы вместо условной компиляции написал бы P/Invoke трех функций и вызвал бы нужную в зависимости от версии AutoCAD (Application.Version). Но это на любителя... Что касается замены кода, то акцентирую внимание на то, что ты принудительно подменяешь код, который был ранее. Если в коде были обработчики событий, то (так как ты их не отключаешь), они будут ссылаться на старые, заменённые тобой функции. А это значит, что крах неизбежен. Так что будь очень осторожен.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
P.P.S. Не факт, что размер bool == 1 (ибо определяется реализацией), у MS, да == 1. Ну и + там всегда false. Честно говоря, я думал компилятор сам разберётся.
Как раз нет. Почитай тему: http://adn-cis.org/forum/index.php?topic=1719.0 Там как раз ошибка вылезла именно из-за того, что использовался (по-умолчанию) UnmanagedType.Bool вместо UnmanagedType.I1.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Дима_

  • ADN Club
  • ****
  • Сообщений: 473
  • Карма: 66
Я бы вместо условной компиляции написал бы P/Invoke трех функций и вызвал бы нужную в зависимости от версии AutoCAD (Application.Version). Но это на любителя...
Если не секрет - в чем причина предпочтений, если только не из желания загружать одну и ту же сборку в разные версии.

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

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Если не секрет - в чем причина предпочтений, если только не из желания загружать одну и ту же сборку в разные версии.
Это представь себе сколько конфигураций (и соотвественно количество сборок) нужно иметь для:
Код - C# [Выбрать]
  1. #if R17_2 || R18_0 || R18_1 || R18_2
хотя в большинстве случаев в этом нет необходимости.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн A77X7Автор темы

  • ADN OPEN
  • Сообщений: 20
  • Карма: 0
Я бы вместо условной компиляции написал бы P/Invoke трех функций и вызвал бы нужную в зависимости от версии AutoCAD (Application.Version)
Хорошая идея! Я замучался уже делать сборки под разные версии начиная с 2009й и по 2016ю. Я до недавнего времени думал, что если импортированной функции нет по факту, то программа просто не запустится...
Ещё бы вот здесь как-то избежать условной компиляции:
Код - C# [Выбрать]
  1. #if R17_2 || R18_0 || R18_1 || R18_2
  2. using Autodesk.AutoCAD.ApplicationServices;
  3. using Autodesk.AutoCAD.EditorInput;
  4.  
  5. #elif R19_0 || R19_1 || R20_0 || R20_1
  6. extern alias AcCoreMgd;
  7. using AcCoreMgd.Autodesk.AutoCAD.ApplicationServices;
  8. using AcCoreMgd.Autodesk.AutoCAD.ApplicationServices.Core;
  9. using AcCoreMgd.Autodesk.AutoCAD.EditorInput;
  10.  
  11. #endif
Без этого компилятор ругается на Document, что он определён и в CoreMgd и в Mgd...

Оффлайн A77X7Автор темы

  • ADN OPEN
  • Сообщений: 20
  • Карма: 0
А это значит, что крах неизбежен
Изначальная идея была, чтобы можно было оперативно менять только то, что часто меняется (особенно вначале внедрения чего-то нового), т.к. просто подменить dll-ку теперь нельзя (как раньше FreeLibrary), нужно перезапускать AutoCAD (или ещё что-то). Возиться с AppDoamin + IPC тоже не хочется из-за этого почему-то.
На счёт событий проверю, мне интересно стало просто. Отпишусь потом.

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

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

Оффлайн A77X7Автор темы

  • ADN OPEN
  • Сообщений: 20
  • Карма: 0
По поводу перекомпиляции с подключенными событиями...

Подписываемся на событие (например, Application.DocumentManager.DocumentLockModeChanged += DocumentManager_DocumentLockModeChanged;).
Событие отрабатывает нормально.
Меняем код, перекомпилируем.
Отписаться от старого события уже не можем (Application.DocumentManager.DocumentLockModeChanged -= DocumentManager_DocumentLockModeChanged;), ничего не происходит (исключение, например).
Подписываемся на новую версию события (Application.DocumentManager.DocumentLockModeChanged += DocumentManager_DocumentLockModeChanged;)
Получаем отработку двух версий одного события.
Отписываемся от события (Application.DocumentManager.DocumentLockModeChanged -= DocumentManager_DocumentLockModeChanged;
Получаем отработку только старой версии события.
Ещё раз отписываемся (Application.DocumentManager.DocumentLockModeChanged -= DocumentManager_DocumentLockModeChanged;), ничего не меняется, работает старая версия события.

Если в старом событии есть вызов метода f1 в этом же типе, то при его (метода f1) изменении работает старая версия метода f1.

Итого получается после перекомпиляции старая реализация не заменяется. Новая реализация "лежит" рядом. Если были ссылки на методы (и, думаю,  другое) в старой реализации они остаются и корректно ссылаются на старую реализацию. При получении ссылок после перекомпиляции, "выдаются" ссылки на новую реализацию.

Ничего не обрушилось. Наверное где-то в МСДН об этом написано. Всё ведь делается штатными средствами, без всякого хака.
« Последнее редактирование: 25-01-2016, 10:52:09 от A77X7 »

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

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