Вышла новая версия Revit — время пересобирать плагины для поддержки новой версии!
Revit API от версии к версии меняется, и что делать, если вы написали какой-то плагин и хотите, чтобы он работал под разными версиями Revit? Конечно, можно просто сделать копию всего решения и подправить под новую версию, но как тогда вносить изменения — в каждую копию отдельно? Ну уж нет!
Решить задачу можно разными способами, опишу решение, к которому сам пришел.
К сожалению, в стандартном интерфейсе Visual Studio задачу не решить: там можно вводить несколько «конфигураций», но нам этого мало — ведь ещё и нужно подключать разные версии библиотек Revit API. К счастью, возможность всё-таки есть, но нужно будет подредактировать файлы вручную! Я буду использовать Notepad++ и собирать под версии Revit 2017-2022.
Для начала, конечно, надо закрыть Visual Studio. Далее открываем sln-файл в блокноте (предварительно сделайте резервную копию!). Нас интересуют вот эти две секции:
Здесь мы как раз вводим «Конфигурации сборки». В первой секции меняем текст на следующий:
R2017|Any CPU = R2017|Any CPU R2018|Any CPU = R2018|Any CPU R2019|Any CPU = R2019|Any CPU R2020|Any CPU = R2020|Any CPU R2021|Any CPU = R2021|Any CPU R2022|Any CPU = R2022|Any CPU R2023|Any CPU = R2023|Any CPU R2024|Any CPU = R2024|Any CPU R2025|Any CPU = R2025|Any CPU
Во второй секции обратите внимание на GUID в фигурных скобках. Сохраните его где-нибудь, он сейчас пригодится. Вставляем этот текст, но заменяем guid на свой:
{замените здесь на свой guid}.R2017|Any CPU.ActiveCfg = R2017|Any CPU {замените здесь на свой guid}.R2017|Any CPU.Build.0 = R2017|Any CPU {замените здесь на свой guid}.R2018|Any CPU.ActiveCfg = R2018|Any CPU {замените здесь на свой guid}.R2018|Any CPU.Build.0 = R2018|Any CPU {замените здесь на свой guid}.R2019|Any CPU.ActiveCfg = R2019|Any CPU {замените здесь на свой guid}.R2019|Any CPU.Build.0 = R2019|Any CPU {замените здесь на свой guid}.R2020|Any CPU.ActiveCfg = R2020|Any CPU {замените здесь на свой guid}.R2020|Any CPU.Build.0 = R2020|Any CPU {замените здесь на свой guid}.R2021|Any CPU.ActiveCfg = R2021|Any CPU {замените здесь на свой guid}.R2021|Any CPU.Build.0 = R2021|Any CPU {замените здесь на свой guid}.R2022|Any CPU.ActiveCfg = R2022|Any CPU {замените здесь на свой guid}.R2022|Any CPU.Build.0 = R2022|Any CPU {замените здесь на свой guid}.R2023|Any CPU.ActiveCfg = R2023|Any CPU {замените здесь на свой guid}.R2023|Any CPU.Build.0 = R2023|Any CPU {замените здесь на свой guid}.R2024|Any CPU.ActiveCfg = R2024|Any CPU {замените здесь на свой guid}.R2024|Any CPU.Build.0 = R2024|Any CPU {замените здесь на свой guid}.R2025|Any CPU.ActiveCfg = R2025|Any CPU {замените здесь на свой guid}.R2025|Any CPU.Build.0 = R2025|Any CPU
Результат будет примерно такой:
Готово, сохраняем и закрываем этот файл.
Далее будет посложнее. Заходим в папку с решением и открываем csproj-файл (для него тоже не забудьте сделать резервную копию!). В нём нам предстоит задать, что именно будет делать Студия в зависимости от выбранной конфигурации. Этот файл имеет xml-синтаксис: <Свойство> Содержимое </Свойство>. Надо не забывать, что у каждого открывающего тэга должен быть закрывающий с таким же именем, помеченный значком слэш /. В Notepad++ есть подсветка синтаксиса и работать достаточно удобно.
Структура файла будет примерно следующая:
<Project> //начальные настройки не трогаем <PropertyGroup> Общие настройки не трогаем </PropertyGroup> <PropertyGroup> Добавляем особые настройки под R2017 </PropertyGroup> <PropertyGroup> Особые настройки под R2018 и т.д. </PropertyGroup> <ItemGroup> Общие подключаемые библиотеки </ItemGroup> <Choose> <When Condition = 2017> Подключаемые библиотеки для R2017 </When> <When Condition = 2017> Подключаемые библиотеки для R2018, и т.д. </When> </Choose> //остальные настройки не трогаем </Project>
Главная магия будет происходить в блоке Choose/When: как раз здесь мы можем указать, что в зависимости от конфигурации будут подключаться разные библиотеки. Намечаем план корректировок:
Смотрим блок конфигурации под конкретную версию. Содержимое его будет примерно такое:
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'R2017|AnyCPU' "> <DebugSymbols>true</DebugSymbols> <DebugType>full</DebugType> <Optimize>false</Optimize> <OutputPath>bin\R2017\</OutputPath> <DefineConstants>DEBUG;R2017</DefineConstants> <TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion> <AssemblyName>$(AssemblyName)_2017</AssemblyName> </PropertyGroup>
Опции DebugSymbols, Optimise и DebugType нужны, чтобы работала отладка и присоединение к процессу Revit в VisualStudio.
OutputPath — папка, куда будет складироваться dll-ка. У меня сделано, что каждая версия будет складываться в папку с номером версии. AssemblyName, соответственно, — шаблон имени dll-файла, у меня будет как ИмяРешения_НомерВерсии.dll.
DefineConstants — важная вещь, это «ключи для компиляции», которые можно будет использовать в коде (далее покажу).
TargetFramework — какую версию .Net Framework использовать при сборке:
- Revit 2017: v4.5.2
- Revit 2018: v4.6
- Revit 2019, 2020: v4.7
- Revit 2021, 2022: v4.8
.NET Framework устанавливается вместе с Ревитом, но только «облегченная» версия — для запуска готовых приложений, не для их сборки. Нужно установить именно версии Developer Pack:
Итак, копируем PropertyGroup столько раз, сколько у нас конфигураций, и внимательно меняем значения на нужные нам:
Далее в секции ItemGroups удаляем блоки Reference со ссылками на библиотеки Revit и после окончания этой ItemGroup добавляем секцию Choose/When:
«When», соответственно, дублируем столько же раз, сколько у нас конфигураций.
Готово! Сохраняем файл и открываем решение в VisualStudio. В списке сверху должны появиться все заданные конфигурации, и если их переключать — будет видно, что меняется путь в свойствах подключенных RevitAPI и RevitAPIUI:
Но для чего мы всем этим занимались? Для того, чтобы можно было использовать символы условной компиляции! Изменения в Revit API обычно вносятся небольшие, и весь код остается неизменный, но где-то в одном месте выдает ошибку из-за изменений в API. Например, свойство Rebar.Normal работает в Revit 2017, но в 2018 уже помечено как «Устаревшее», а в 2019 просто будет выдавать ошибку:
Мы можем просто «обернуть» этот блок кода и сказать, чтобы он выполнялся только для одной конфигурации, а для другой — игнорировался! Это делается синтаксисом #if #endif. Обратите внимание, как при переключении «текущей конфигурации» код «отключается» и вообще не будет компилироваться.
R2017 после #if — это как раз то, что мы ранее указывали в DefineConstants. Можно вводить несколько через ||.
Если в тот момент, когда выбрана какая-то конфигурация, запустить «Пересобрать проект», то соберется dll именно с нужным кодом и подключенными библиотеками и сохранится в нужной папке.
Но можно сделать ещё круче — использовать Пакетную сборку! Зайдите Build — Batch Build, просто отметьте все флажки, нажмите «Пересобрать» и разом получите набор dll-ок под каждую версию Revit:
Что-то не получилось? Вот примеры файлов на Github: sln, csproj.
Успехов в изучении C# и Revit API!