Несколько плагинов с общими библиотеками

Автор Тема: Несколько плагинов с общими библиотеками  (Прочитано 16603 раз)

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

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

  • ADN OPEN
  • Сообщений: 39
  • Карма: 0
Добрый день!
В нашей компании есть следующая проблема: имеется несколько плагинов использующих общие библиотеки. При этом, если на машине установлен один из плагинов, и рядом ставится второй плагин с обновлённой общей библиотекой, то возникает конфликт. Любой из установленных плагинов может не находить нужных методов (если сигнатура метода была изменена), или же использовать методы из старой библиотеки.
Каким образом можно решить эту проблему?

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

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
Что-то я не понял - если рядом ставится второй плагин с обновленной общей библиотекой, то как тогда могут быть использованы методы из старой библиотеки? Разве они не заменены на новые?

Оффлайн Дмитрий Загорулькин

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Если вы изменяете логику работы метода - то меняйте и имя. В конце-концов, можно просто добавлять циферки на конце (SuperPuperMethod, SuperPuperMethod1...). А если добавляете новый метод с другой сигнатурой, то конфликтов по идее быть не должно (в NET).

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

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

.NET гораздо более гибок, чем COM. Например, ты можешь править уже имеющиеся старые интерфейсы, добавляя новые методы и всё при этом будет работать. Главное при этом - не трогать уже имеющиеся старые, иначе получишь то, что ты получил. Тогда конфликтов быть не должно, насколько мне известно. По факту, в твоём случае, ноги растут от плохого проектирования. Прежде чем садиться писать код, неплохо было бы для начала (помимо анализа проблемы) выполнить проектирование и лишь затем садиться за реализацию. В процессе проектирования в т.ч. заранее продумываются и программные интерфейсы с учётом дальнейших возможных изменений.

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

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

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

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

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

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

Если говорить о варианте, когда сохраняются разные версии DLL (то ли под разные версии CAD, то ли под разные версии .NET, то ли оба варианта вместе)... Разные версии AutoCAD используют разные версии .NET Framework. Т.о. в одном каталоге разместить одноимённые DLL, собранные под разные версии .NET не получится. Варианта два:
  • давать разные имена DLL файлам, например добавляя различного рода суффиксы, указывающие либо целевую версию CAD (.R17.2, R18.0, и т.д.) либо указывающие версию CLR, если это общая DLL, не связанная с AutoCAD .NET API
  • помещать DLL по отдельным подкаталогам (в этом случае DLL имеют одинаковые имена). В runtime вычисляется нужный подкаталог и грузится нужная DLL.
За всю свою историю работы я ни разу не столкнулся с проблемами в работе своих .NET плагинов, использующих мною же созданных  (и, по мере необходимости, обновляемых) общих DLL. Это обусловлено в первую очередь тем, что очередная версия DLL не изменяет состав и сигнатуры уже существующих методов. Я могу добавлять новые или изменять реализацию, но не меняю "старые контракты". Взаимодействие выполняю, как правило, посредством интерфейсов.

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

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

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

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

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

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

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

  • ADN OPEN
  • Сообщений: 39
  • Карма: 0
В качестве эксперимента сделал следующие: загружаю плагин1 (использует более раннюю версию общей библиотеки), затем загружаю плагин2(использует обновлённую версию общей библиотеки). Потом в VS посмотрел загруженные модули, и получается, что в такой ситуации, общая библиотека подгружаемая плагином2 - игнорируется (в памяти висит только библиотека плагина1).
Вариантом был бы StrongName, но сделать это невозможно, т.к. библиотеки Акада которые используются - не подписаны.

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

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Вариантом был бы StrongName, но сделать это невозможно, т.к. библиотеки Акада которые используются - не подписаны.
давно известный факт, причём автодеск утверждает, что это безобразие создано специально.
« Последнее редактирование: 01-07-2015, 10:50:33 от Андрей Бушман »

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

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Только сейчас заметил, что на мой вопрос в комментах по обозначенной выше ссылке ответили. Что же, на первый взгляд аргументация выглядит достаточно разумной.
« Последнее редактирование: 01-07-2015, 10:51:45 от Андрей Бушман »

Оффлайн Дмитрий Загорулькин

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Эх, поднимем такую хорошую тему :)
Тоже столкнулся с проблемой общих сборок.
Ситуация такая: есть несколько приложений, которые используют несколько общих вспомогательных DLL. Одна библиотека расширяет функционал AutoCAD API, вторая - Civil 3D API, третья - вспомогательная библиотека с механизмом реализации ссылок между объектами чертежа, ну и т.д. Каждое приложение имеет свой собственный инсталлятор и устанавливается отдельно в свою папку Bundle. Соответственно, каждое из приложений тянет в свою папку эти вспомогательные DLL. Упрощенная схема на рисунке Current. Так вот, если я внес какие-то изменения во вспомогательные DLL, пересобрал приложения, создал новые инсталляторы и отправил пользователям, но они по какой-то причине не обновили все приложения, то возникают вполне логичные различные неполадки несовместимости при их загрузке в AutoCAD. Со стороны пользователя, это, конечно же, значительное неудобство. Получается, я облегчаю себе жизнь, как разработчику, вынося повторяющийся функционал в общие библиотеки, но этим усложняю жизнь пользователям. Думаю, что это не очень хорошо.
Как выход из этой ситуации, мне видится создание отдельной инсталляции для вспомогательных библиотек. Можно это сделать в виде отдельного компонента и внедрять как необходимый компонент в инсталлятор каждого приложения. При установке, будет проверяться версия установленного пакета библиотек и, при необходимости, обновляться. Схема не нова, нечто похожее используют многие инсталляторы приложений Windows. Взять, хотя бы, для примера, установку нужной версии .NET Framework при установке AutoCAD.
Разумеется, помещать пакет библиотек логично в таком варианте в отдельном Bundle. Упрощенная схема на рисунке Project. На первый взгляд, вроде работоспособно. Каких-то проблем с технической реализацией этой схемы я пока не вижу. Но нужно как-то обеспечить загрузку вспомогательных библиотек раньше загрузки всех приложений, которые их используют. Иначе AutoCAD их сам не найдет и не загрузит, когда DLL приложения запросит какой-нибудь объект из вспомогательной DLL, и загрузка приложения прервется ошибкой. Как я понимаю, загрузка Bundle выполняется в AutoCAD по алфавитному порядку названий папок Bundle в каталоге ApplicationPlugins. Получается, что нужно обеспечить папке Bundle с библиотечными DLL такое название, чтобы она была "выше всех". На мой взгляд, это довольно "топорный" способ т.к. нет гарантии, что AutoCAD и дальше будет так загружать пакеты. С его точки зрения все Bundle равнозначны и независимы. Да и хотелось бы давать свободные названия для папок Bundle, а не что-то типа "0Library.bundle", "1Application1.bundle", "2Application2.bundle". Но, пока, ничего лучше придумать не могу. Может быть, есть у кого-то интересные идеи по данному вопросу? Или критические замечания по такой схеме?
Спасибо.

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

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

Оффлайн Дмитрий Загорулькин

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Во-первых не следует полагаться на порядок загрузки. Я не проверял, но мне кажется, что он читает каталоги внутри ApplicationPlugins и обрабатывает их не в алфавитном порядке, а в том порядке в котором они находятся в каталоге (а это совершенно необязательно отсортированные по алфавиту).
Вот да, именно так! На уровне подсознания где-то, есть понимание, что это весьма ненадежно :)
Во-вторых, я бы предпочел в методе Initialize своих приложений загружать необходимые сборки если они еще не загружены, а если их загрузить не удаётся, то сообщал бы пользователю.
А это уже весьма интересная идея! Надо будет проверить, как это будет работать.
В-третьих, я бы вообще не включал их ни в какие BUNDLE'ы - если это библиотечные файлы, то зачем отдавать их загрузку на волю AutoCAD?
Да, согласен. Если Ваша идея с подгрузкой из Initialize хорошо покажет себя в работе, то от загрузки библиотеки через bundle можно отказаться.
Попробую сделать небольшой тестовый проект и обкатать идею.
Спасибо!

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

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

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

  • ADN Club
  • ****
  • Сообщений: 473
  • Карма: 66
Я в этом моменте плюю на размер в угоду надежности. В БД если обновляется любой компонент, то автоматом создается архив со всеми сборками и пр. компонентами и при загрузке автокада "загрузчик" увидев новую версию в БД все переписывает на локальном компе (с учетом "уровня" пользователя) - то есть чистит все "свои" сборки и разворачивает по новой весь загруженный архив. И если что, можно в момент откатить до любой предыдущей версии - пока правда такое "счастье" миновало, но все возможно.

Оффлайн Дмитрий Загорулькин

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Главное, чтобы у тебя не было статических переменных, которые инициализируются значениями, использующие классы и методы из этих "библиотек". Насколько я помню инициализация статических переменных происходит до вызова метода Initialize (могу ошибаться).
Нет, не ошибаетесь. Это естественное поведение при загрузке любого .NET класса.
Как показали опыты, в самом Initialize, после кода подгрузки вспомогательных DLL, также нельзя использовать методы из этих DLL. Если раскомментить строки 44-46 (обращения к методам вспомогательных библиотек), то метод Initialize не выполнится и DLL с этим кодом не будет загружена. Не знаю, почему так. Возможно, что это тоже естественное поведение .NET, но я с таким еще не сталкивался.
Код - C# [Выбрать]
  1. using Autodesk.AutoCAD.ApplicationServices;
  2. using Autodesk.AutoCAD.EditorInput;
  3. using Autodesk.AutoCAD.Runtime;
  4. using System;
  5. using System.IO;
  6. using System.Reflection;
  7.  
  8. namespace Application1
  9. {
  10.     public class AppInitClass : IExtensionApplication
  11.     {
  12.         static bool AssemblyLoad(string path)
  13.         {
  14.             try
  15.             {
  16.                 Assembly.LoadFrom(path);
  17.                 return true;              
  18.             }
  19.             catch (System.Exception ex)
  20.             {                
  21.                 Application.ShowAlertDialog($"Exception: {ex.Message}");
  22.                 return false;
  23.             }            
  24.         }
  25.  
  26.         public void Initialize()
  27.         {
  28.             string appsDirPath = Path.Combine
  29.                 (Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData),
  30.                 "Autodesk", "ApplicationPlugins", "AppLibrary");
  31.  
  32.             string myLib1Path = Path.Combine(appsDirPath, "MyLibrary1.dll");
  33.             string myLib2Path = Path.Combine(appsDirPath, "MyLibrary2.dll");
  34.             string myLib3Path = Path.Combine(appsDirPath, "MyLibrary3.dll");
  35.  
  36.  
  37.             if (!AssemblyLoad(myLib1Path)
  38.                 || !AssemblyLoad(myLib2Path)
  39.                 || !AssemblyLoad(myLib3Path))
  40.             {
  41.                 return;
  42.             }
  43.  
  44.             //Document adoc = MyLibrary1.Support1.GetActiveDocument(Application.DocumentManager);
  45.             //string appName = MyLibrary2.Support2.GetAppName(Assembly.GetExecutingAssembly());
  46.             //string adocName = MyLibrary3.Support3.GetAdocName(adoc);
  47.  
  48.             Application.ShowAlertDialog("Application #1 loaded!");            
  49.         }
  50.  
  51.         public void Terminate()
  52.         {
  53.  
  54.         }
  55.  
  56.         [CommandMethod("App1Test")]
  57.         public void Run()
  58.         {
  59.             Document adoc = MyLibrary1.Support1.GetActiveDocument(Application.DocumentManager);
  60.             string appName = MyLibrary2.Support2.GetAppName(Assembly.GetExecutingAssembly());
  61.             string adocName = MyLibrary3.Support3.GetAdocName(adoc);
  62.  
  63.             Application.ShowAlertDialog("Application #1 test cmd: OK");
  64.             Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
  65.             ed.WriteMessage("\nApplication #1 test cmd: OK");
  66.         }
  67.     }
  68. }
  69.  
« Последнее редактирование: 11-02-2020, 10:43:23 от Дмитрий Загорулькин »

Оффлайн Дмитрий Загорулькин

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Я в этом моменте плюю на размер в угоду надежности. В БД если обновляется любой компонент, то автоматом создается архив со всеми сборками и пр. компонентами и при загрузке автокада "загрузчик" увидев новую версию в БД все переписывает на локальном компе (с учетом "уровня" пользователя) - то есть чистит все "свои" сборки и разворачивает по новой весь загруженный архив. И если что, можно в момент откатить до любой предыдущей версии - пока правда такое "счастье" миновало, но все возможно.
У меня "загрузчиков" никаких нет. Для приложений я создаю инсталляторы с помощью WIX. Наверное, в проект инсталляции тоже можно добавить программу, которая будет анализировать уже имеющиеся приложения и библиотеки в них, но я пока до этого не дорос.

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

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

Оффлайн Дмитрий Загорулькин

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Да нет, исключений там не происходит. Да я, на самом деле, уже что только не делал  :) И по отдельности пробовал раскомментить, и обработку ошибок, и логику методов вспомогательных менял. Ничего не помогает.
Я подозреваю, что есть какой-то механизм проверки обращений метода Initialize к сторонним DLL, и если они в момент обращения к методу недоступны, то сам метод не выполняется. Потому что при дебаге даже не срабатывает точка останова на входе в метод, если хотя бы одна из этих строк не закомментирована.

Оффлайн Дмитрий Загорулькин

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Главное, чтобы у тебя не было статических переменных, которые инициализируются значениями, использующие классы и методы из этих "библиотек".
Ваш совет натолкнул меня на идею - вынести загрузку библиотек в статический конструктор класса. В таком варианте работает как надо! Еще раз, спасибо за идею! Теперь надо обкатать ее на рабочих сборках.
Итоговый код автозагружаемого класса
Код - C# [Выбрать]
  1. using Autodesk.AutoCAD.ApplicationServices;
  2. using Autodesk.AutoCAD.EditorInput;
  3. using Autodesk.AutoCAD.Runtime;
  4. using System;
  5. using System.IO;
  6. using System.Reflection;
  7.  
  8. namespace Application1
  9. {
  10.     public class AppInitClass : IExtensionApplication
  11.     {
  12.         /// <summary>
  13.         /// Статический конструктор класса
  14.         /// </summary>
  15.         static AppInitClass()
  16.         {
  17.             // составляем путь к папке с библиотечными DLL
  18.             // в данном случае %ProgramData%\Autodesk\ApplicationPlugins\AppLibrary
  19.             string appsDirPath = Path.Combine
  20.                 (Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData),
  21.                 "Autodesk", "ApplicationPlugins", "AppLibrary");            
  22.  
  23.             // грузим библиотечные DLL
  24.             AssemblyLoad(Path.Combine(appsDirPath, "MyLibrary1.dll"));
  25.             AssemblyLoad(Path.Combine(appsDirPath, "MyLibrary2.dll"));
  26.             AssemblyLoad(Path.Combine(appsDirPath, "MyLibrary3.dll"));
  27.         }
  28.  
  29.         /// <summary>
  30.         /// Безопасный метод загрузки DLL
  31.         /// </summary>
  32.         /// <param name="path">Путь к DLL</param>
  33.         /// <returns>true - загружена, false - не загружена</returns>
  34.         static bool AssemblyLoad(string path)
  35.         {
  36.             try
  37.             {
  38.                 Assembly.LoadFrom(path);
  39.                 return true;
  40.             }
  41.             catch (System.Exception ex)
  42.             {
  43.                 Application.ShowAlertDialog($"Exception: {ex.Message}");
  44.                 return false;
  45.             }
  46.         }
  47.  
  48.         /// <summary>
  49.         /// Метод, выполняемый AutoCAD при загрузке сборки
  50.         /// </summary>
  51.         public void Initialize()
  52.         {
  53.             // Вызываем методы из библиотечных DLL, по одному из каждой
  54.             Document adoc = MyLibrary1.Support1.GetActiveDocument(Application.DocumentManager);
  55.             string appName = MyLibrary2.Support2.GetAppName
  56.                 (Assembly.GetExecutingAssembly()) ?? "*no_app_name*";
  57.             string adocName = MyLibrary3.Support3.GetAdocName(adoc) ?? "*no_adoc_name*";
  58.  
  59.             // Выводим сообщение
  60.             Application.ShowAlertDialog($"{appName} loaded into {adocName}!");
  61.         }        
  62.  
  63.         public void Terminate()
  64.         {
  65.  
  66.         }
  67.  
  68.         /// <summary>
  69.         /// Командный метод для проверки загруженности сборки
  70.         /// </summary>
  71.         [CommandMethod("App1Test")]
  72.         public void Run()
  73.         {
  74.             Document adoc = MyLibrary1.Support1.GetActiveDocument(Application.DocumentManager);
  75.             string appName = MyLibrary2.Support2.GetAppName
  76.                 (Assembly.GetExecutingAssembly()) ?? "*no_app_name*";
  77.             string adocName = MyLibrary3.Support3.GetAdocName(adoc) ?? "*no_adoc_name*";
  78.  
  79.             Application.ShowAlertDialog($"{appName} test command in {adocName}: OK");
  80.             Editor ed = adoc?.Editor;
  81.             ed?.WriteMessage("\n{0} test command in {1}: OK", appName, adocName);
  82.         }
  83.     }
  84. }

Тестовый проект - в архиве (VS 2015)
« Последнее редактирование: 11-02-2020, 10:43:05 от Дмитрий Загорулькин »

Оффлайн Вильдар

  • ADN Club
  • ****
  • Сообщений: 405
  • Карма: 77
  • Skype: vildar82
Со сторонними библиотеками есть проблемы - использования разных версий в разных плагинах.
Есть предположение, что лучший способ - строгие имена и регистрация в гаке!
Правда, пока на практике не проверял  ::)
И есть много библиотек без строгих имен.

Оффлайн Дмитрий Загорулькин

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Со сторонними библиотеками есть проблемы - использования разных версий в разных плагинах.
Я уже третий год использую схему, которую описал в предыдущем своём сообщении в этой теме - такой проблемы у меня больше нет.
Нужно придерживаться нескольких правил. Например - ничего не удалять из библиотечной DLL. Можно менять внутренности, но все публичные члены должны быть неизменными. Если что-то перестаёт быть актуальным - помечаю как Obsolete. Библиотечные dll собираю в отдельные MergeModule и добавляю в проект установки каждого плагина. При установке плагина, все вспомогательные DLL, которые он использует, обновляются до новых версий. Но так как из них ничего старого не удаляется, то и старые плагины спокойно используют обновлённые DLL.
Проблема помещения вспомогательных DLL для AutoCAD в GAC была описана ещё Бушманом Андреем, где-то тут есть на форуме, если поискатьобнаружил, что обсуждение этого вопроса - как раз в этой теме ранее было :). Если я правильно помню, суть в том, что DLL из AutoCAD API не подписаны и если в библиотечной DLL есть ссылка на них, то в GAC они не могут быть помещены. Теоретически, конечно, есть вариант писать библиотеки без привязки к AutoCAD API, но, по мне, затрат будет больше, чем выгоды.

Оффлайн Роман Малютин

  • ADN Club
  • Сообщений: 15
  • Карма: 3
  • Инженер
    • lep10.ru
Ещё раз подниму эту прекрасную тему про совместимость  :)

SQLite - суперпопулярная технология хранения данных.
Плагин#1 использует System.Data.SQLite.dll v.1.0.97, загружается первым, разработан третьей стороной.
Плагин#2 использует System.Data.SQLite.dll v.1.0.112, загружается вторым, мой
Результат - AutoCAD падает с фатальной ошибкой.
Если скопировать более свежую System.Data.SQLite.dll из Плагина#2 в Плагин#1 - всё работает.

Пробовал грузить dll как писал Дмитрий Загорулькин, чтобы получить информацию об ошибке - не вышло.
Подскажите хотя бы направление поиска проблемы. Сигнатуры там не менялись, обычный IDbConnection ...

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

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Если скопировать более свежую System.Data.SQLite.dll из Плагина#2 в Плагин#1 - всё работает.
Собственно говоря это единственный мне известный метод. Две разных версии одной сборки загрузить в один домен нельзя.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Вильдар

  • ADN Club
  • ****
  • Сообщений: 405
  • Карма: 77
  • Skype: vildar82
Можно переименовать дллку и грузить ее принудительно. В некоторых случаях помогает.

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

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Вильдар,
Судя по тому, что написано здесь: https://system.data.sqlite.org/index.html/doc/trunk/www/downloads.wiki там используются не только managed, но и native dll-файлы. Так что в этом случае точно ничего не получится. Разве что скачать исходники, поменять везде имена и перекомпилировать.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Вильдар

  • ADN Club
  • ****
  • Сообщений: 405
  • Карма: 77
  • Skype: vildar82
там используются не только managed, но и native dll-файлы
ох, с таким еще не сталкивались, слава богу 😁

Оффлайн Роман Малютин

  • ADN Club
  • Сообщений: 15
  • Карма: 3
  • Инженер
    • lep10.ru
Собственно говоря это единственный мне известный метод. Две разных версии одной сборки загрузить в один домен нельзя.
Спасибо. Ох, это прям фиаско.
Может мой вопрос покажется дилетантским и риторическим, но вот интересно, как в компании Autodesk предполагали работу их системы? В плагинах же повсеместно используются популярные библиотеки для типовых операций - работа с БД, экспорт данных в Excel/Word/PDF, всякие там ORM, мапперы... Получается, что конфликт просто неизбежен?
Только в App Store более 4000 приложений, думаю там немало на .net.
Заставлять пользователя рыться в файлах плагинов и выискивать конфликтные библиотеки - это конечно рабочее решение, но в 99% случаев сами знаете что будет.

Можно переименовать дллку и грузить ее принудительно. В некоторых случаях помогает.
Просто сменить имя файла? Проверял, не сработало.

В своем проекте выставил для System.Data.SQLite.dll свойство 'Specific version'=false. Надеюсь, это хоть немного увеличит шансы пользователей в нелегком деле копирования файлов  :)

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

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Может мой вопрос покажется дилетантским и риторическим, но вот интересно, как в компании Autodesk предполагали работу их системы?
1. Причем здесь AutoCAD? Это касается любого exe-файла, для которого создаётся система плагинов. Тут скорее претензия к Microsoft, что они не предусмотрели такое...
2. Кто заставляет тебя пользоваться сторонними библиотеками в своих приложениях? Для ObjectARX допустима вообще только конкретная версия Visual Studio с конкретным пакетом обновлений. И ничего - никто не жалуется. :-)
В своем проекте выставил для System.Data.SQLite.dll свойство 'Specific version'=false. Надеюсь, это хоть немного увеличит шансы пользователей в нелегком деле копирования файлов 
Теоретически это могло бы помочь если бы под капотом не использовались native dll-файлы. А так очень сомнительно...
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Дмитрий Загорулькин

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Получается, что конфликт просто неизбежен?
Да, это так. Даже если сделать систему распространения своих приложений таким образом, чтобы исключались конфликты версий вспомогательных библиотек, это не поможет, если используются сторонние плагины с теми же библиотеками других версий. Я, например, тоже System.Data.SQLite использую в одном из плагинов. И я не помню, когда последний раз его версию обновлял.
Возможно, в случае с SQLite можно как-то избежать проблемы, если найти возможность использовать те же самые DLL, которые использует сам AutoCAD для работы с ней. Где-то среди его файлов установки я находил библиотеки SQLite. Но, возможно, что это только в Civil 3D. И, скорее всего, там используется Native версия SQLite.

Оффлайн avc

  • ADN Club
  • *****
  • Сообщений: 809
  • Карма: 166
    • Мои плагины к Автокаду
Получается, я облегчаю себе жизнь, как разработчику, вынося повторяющийся функционал в общие библиотеки, но этим усложняю жизнь пользователям.
Вот именно. И это одна из причин, почему я пошел обратным путем - один плагин = одна dll. Ни каких вспомогательных. А исходные коды во всех проектах плагинов на 90% одни те же - вставлены в проект как ссылки. Да, я теряю в скорости компиляции, вынужден заталкивать все новые файлы CS во все проекты. Зато у пользователя нет проблем совместимости.

Оффлайн Дмитрий Загорулькин

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
avc, адаптеры к БД тоже свои пишете?  :)

Оффлайн avc

  • ADN Club
  • *****
  • Сообщений: 809
  • Карма: 166
    • Мои плагины к Автокаду
Неее :) Доступ к SQL встроен в .Net - им и пользуюсь. А если что-то надо подключить - вариант только искать open source. Пока все что надо находил :)

Оффлайн Роман Малютин

  • ADN Club
  • Сообщений: 15
  • Карма: 3
  • Инженер
    • lep10.ru
1. Причем здесь AutoCAD? Это касается любого exe-файла, для которого создаётся система плагинов. Тут скорее претензия к Microsoft, что они не предусмотрели такое...
Претензия не к функционалу. Просто факт не очевидный. На месте человека, который выбирает язык программирования под AutoCAD, я бы хотел это узнать как можно раньше.

Из-за меня тут люди пострадали. Делали-делали свой шедевр, а в итоге пользователь просто удалил их плагин, т.к. он конфликтует с моим. А могло быть и наоборот! :-\

Попытался проскочить нахаляву:
Код - INI [Выбрать]
  1. ildasm /all /out=System.Data.SQLite.il System.Data.SQLite.dll
  2. (правка il файла в VS Code)
  3. ilasm /dll /out=System.Data.SQLite222.dll System.Data.SQLite222.il
Не вышло. Переименовать получилось, работает, но всё равно конфликтует. Теперь застрял на PublicKeyToken. Видимо все же придется компилировать из исходников...

Оффлайн Дмитрий Загорулькин

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Сигнатуры там не менялись, обычный IDbConnection ...
Может попробовать через рефлексию? Если вызовов не сильно много, может и не сильно сложно получится.

Оффлайн Роман Малютин

  • ADN Club
  • Сообщений: 15
  • Карма: 3
  • Инженер
    • lep10.ru
Итак, вот чем закончилась моя история с SQLite:
Поковырял исходники - не моя лига  :) Там такой навороченный MSBuild, что Visual Studio даже файлы классов внутри проекта отобразить не может. Всё подключается на каком-то лютом автомате.

Плюнул я на это дело, и обратился к фрилансерам. $40 - цена вопроса на Upwork. Курс доллара конечно огорчает, зато теперь у меня есть "своя" dll для SQLite, которая ни с кем не конфликтует.
Исходники не понадобились, исправили готовую dll. Сравнил il-код до и после - много мелких изменений, мне не понятных. Похоже софтинка какая-то есть специальная.
Всем спасибо за поддержку.

Оффлайн Дмитрий Загорулькин

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Тоже вариант  :)