how to maintain revit plug-ins for multiple versions

image by archi-lab

One thing that we all have a love/hate relationship with is API breaking changes. Yes, we all love shiny new toys, but they usually break our old reliable tools. What about that one user in the office who still works on a project from 5 years ago, and refuses to update to latest Revit 2018? Do I have to maintain a version of my plug-in for that guy too? The answer is probably yes. How can we go about maintaining code for multiple versions of Revit, and easily building it for any version at any time. Below is a few tips and tricks:

I start off my every Revit plug-in project by creating a Post-Build Event that copies my freshly minted DLL to Autodesk/Addins folder. That usually saves me a few seconds every time I want to launch Revit to see my new tool in action. Now, how can we connect our Post-Build Events with our Configurations settings so that we can build these tools for different version on a fly? Here’s an example of conditional statements embedded into Post-Builds so that we can quickly change between versions:

Let’s break that down a little bit first:

  • echo” is used here to print something to the console. In this case the selected Configuration name.
  • if $(Configuration) == 2017 goto 2017” basically means that if I select Configuration named “2017” please jump over to piece of code that starts with “:2017
  • Here we print another message to the console.
  • Here we check if folder exists at Revit\Addins\2017\OpenAEC since that’s the location we want to copy our new DLLs into. If it doesn’t exist create it first.
  • Notice use of %ALLUSERPROFILE% shortcode for C:\Users\user\AppData\ location. That way we can build our code on any machine under any user name.
  • Finally we have “goto exit” statement so that our code jumps to “:exit” and since that’s the last line, it will just exit out.

Here’s how to create the appropriate Configuration settings:

First open the Configurations Manager:

Then create a new settings by copying/renaming an old one:

If you want to launch the appropriate version of Revit for debugging you can set that under properties:



This can be set for each Configuration, so you can launch different version of Revit for every Configuration. That’s pretty handy when debugging. Next, we can set the Configuration’s Conditional compilation symbols. What is that? I will show you an example in a second but first let’s create one:

Here’s how to use one:

What happens here is that when you build your code, it will omit certain parts of it, based in the conditional statement. This is how you can create a single plug-in that supports multiple versions of Revit.

Finally, each one of these plug-ins needs to have a different reference of RevitAPI.DLL and RevitAPIUI.DLL. How do we load one that we need on demand? We can add some conditional statements to our *.csproj file.

In this way, you can easily order drugs at the best price.

That’s it! Now, depending on what Configuration we select, Visual Studio will reference in the appropriate Revit API DLL, omit certain parts of the code from compiling, and finally copy our DLLs into the appropriate Addin folder. All pretty smooth so that we can focus on writing code.

Support archi-lab on Patreon!

39 Comments

  1. Troy Gates says:

    Same method I use. Great write up.

  2. Deyan says:

    Super super useful as always, Konrad.

  3. Daniel Viero says:

    Great post Konrad.
    My question is though: do you have any preferred method then to deploy the *.dll and .addin files onto each user’s computer?
    Do you use a bat routing which you launch from each computer or do you use some professional IT tools like “GoverLAN”?

    thanks a lot

    • Well, I am usually writing them, and I leave deployment to IT. I think they have some BAT scripts that image everyone’s drive every night to one location on a network. that way i am only worried about getting the DLLs and Addin file to that location when they are ready for deployment. IT takes care of it from there on.

    • Troy Gates says:

      I place all of our addin files on a network share. Then use a bat file that contains an xcopy command to copy newer files to the user computers programdata folder at login via GPO.

      This allows me to update the network share and the users get the new addins the next time they login to their computer.

    • Daniel Viero says:

      Konrad,
      Good point and I do totally support it.
      Each one of us, should take care about his own tasks and responsibilities. However, and that is the main reason why I brought it up, sometimes (sadly) the roles overlap a bit and I find myself taking care also about IT.

      Troy,
      It does totally make sense and that was the main reason why I thought a simple .bat file would do the job nicely and tidy. I will try and attach it to the Task Scheduler and run it on a fortnightly basis so whenever I update the file(s) they will get copied also onto each user’s computer.

      Thanks a lot to you both again.

  4. Kevin Bell says:

    I believe different versions of Revit use different versions of dotnet…

    … is it possible to specify which version of dotnet is used by each version of Revit?

    Or does it not matter?

    Thanks

  5. Kevin Bell says:

    Hi Konrad, Another question from me!

    I’ve set up my plugin and toolbar using Conditional Compilation symbols as your post above – all works well.

    My IT team have asked me to produce an installer (MSI file) so that they can deploy the plugin across the office – I’m using Microsoft Visual Studio Installer projects – which I understand is the default for creating installs in VS.

    The output from the various build configurations for the different versions of Revit creates a toolbar2016.dll file and toolbar2016.addon or a toolbar2017.dll file and toolbar2017.addon etc.

    The problem I have is that I cannot get the installer project to conditionally create an MSI depending on the version – I only get toolbar.msi. As each version of the toolbar dll needs to be placed in a different target install folder I essentially need a per version MSI created.

    I’d appreciate your thoughts on how to go about this (I hope I’ve explained it clearly…)

    Thanks.

    • Yeah I know what you mean. If you care to look at source code for Dynamo, it might reveal something interesting. I think they have in it option to install two different versions. I personally use WIX to make installers, and you can customize it pretty well. It’s not the most intuitive of tools, but you can create packages in WIX and get them installed to various locations. I would look into that as it may suit your needs best.

    • Mouheb says:

      Did you find any solution? im stuck at the same problem

  6. Emil says:

    Great article, thanks Konrad!

  7. Dan Tartaglia says:

    Hi Konrad,

    I’ve been old school, curious to try your method.

    Thanks,
    Dan

  8. Rob says:

    Hi Konrad! Thanks for this excellent writeup! I am working through all of the details now. For the most part things are working well. I am using multiple DLL files and multiple versions of Revit. I am also using a .bundle folder and the PackageContents.xml to “autoload” everything from the ProgramData folder for each user. I am hoping you can elaborate on the use of the references.cs file as noted above. Is this just a standard Class added to the project? How is the references.cs file read by the code? I initially wrote my code for 2017, but am now expanding it to work in newer versions and I can’t seem to get the DLLs to load for the newer versions even after breaking down the files into subfolders inside the .bundle folder like Autodesk recommends. I am wondering if the references file might help solve my problem. Thanks!

  9. Andy says:

    Hi Konrad,

    Thank you for this write up. I would like to confirm one hopefully minor detail. In the project itself, when we Add the RevitAPI and RevitAPIUI dll as References do we just insert one version (ie 2015) or all versions we plan to debug (2015 – 2019)? While inserting the Reference information into the csproj file chooses which to debug, when we are writing our code does it automatically have intellisense for all versions we plan to use?

  10. Leland Jobson says:

    Hello Konrad – have been a fan for a long time!

    Some findings in this experience that might be helpful to you or others:

    – In VS, you can right click the project in the Solution Explorer and “Unload Project”, then right click again and hit “Edit .csproj File” for easy .csproj file access.

    – If you’re like me and you want to copy everything from your Debug folder into your Addins folder (so I can copy and paste the code b/w projects), ex:

    copy “$(TargetDir)*.*” “%AppData%\Autodesk\Revit\Addins\2016”

    Then you will need to set Copy Local to false on your Revit dlls. Doing this in the properties inspector doesn’t work, but in the .csproj file you can specify it with False, ex:

    ..\..\..\..\..\..\..\..\..\..\Program Files\Autodesk\Revit 2017\RevitAPIUI.dll
    False

    • Leland! Thanks for the tip. Yes, using a Target to copy files is actually much better then Post Build. It allows you to handle errors a little easier, or even continue if it fails. Much more forgiving approach.

      On that note, I would not want to copy the whole contents of my bin folder to Revit addins folder. I usually end up with bunch of extra directories, resources, and PDB files that I only need for debugging, that I don’t need for testing in Revit. That’s why I prefer to hand pick specific resources that I want copied.

      Other than that I agree 100% with your comment.

  11. Leland Jobson says:

    ^^ Hey my XML didn’t make it through in the comment render correctly: ^^

    See the attached:

    Attachment:  privatefalse.jpg

  12. Hendrick Mose says:

    Hello Konrad, thanks a lot for this informative blog.
    Where do I put the code that makes sure it’s the right reference I use?

    Is it part of the Post-build or a XML file?

    Thank in advance.

    • Hendrick Mose says:

      Oh I can see I can unload the project and edit the csproj. inside Visual Studio, but where should I put in the code? Just a random place?

      • If you reference your DLLs into the project first, then the basic scaffold will be there. You will see a list of all DLLs in the CSPROJ file. You can then just replace then with the above code or edit them to add the conditional statements. Other DLLs should already be in there as well, so you can always just add these next to them as well.

  13. Sébastien Maire says:

    Hi everyone,

    Great post, I’m actually doing the same it works like a charm, plus I did use it in a separate csproj (where I reference each version based on build mode) which I “include” in others avoiding manually defining it in every project.

    I have a question though, what about minor revit revisions ?
    Let’s say foir example I develop a plugin for 2019.0 will it run on 2019.2 ? (probably, as no breaking changes in minor I presume, but can I be sure of it ? is it written somewhere in Revit documentation ?)

    Thanks in advance !

    • minor versions should not have breaking changes. Revit development team is actually phasing old APIs on a 2 year plan, so in 2017 something gets marked as “obsolete”, then it will be deleted from the API by 2019. Gives you two years to update your code. You should be fine.

  14. Ronan says:

    Is there a way that can have only one single output plugin which supports multiple versions of Revit?

    • Yeah, you can. You can probably use Reflection to check if given methods exist before calling them. The only issue with that approach is debugging. You want to have ability to switch between different versions so that you can see which versions has what methods available when debugging.

  15. Ammad says:

    Hallo i am new to revit. i am using revit version 2021 and one of my plugin is in version 2020 and there is no plugin setup is available for revit version 2021.

    Can someone please guide me in detail steps . or maybe link to some video steps. Please i need that plugin for my project. Any help will really be appreciated.

    i tried to followed the step but i dont have any option what you showed in the screenshots.

    Thanks

    • 2020 plugins should work just fine in 2021 so just drop the DLLs into the addins folder and they should be fine. Things won’t work if there were changes between versions, but I am not sure I can help with any of that. It’s specific to your code/plugin, and I don’t have access to either.

      Cheers!

  16. Lavar Ball says:

    Hi Konrad! Can you clarify if the change in calling out the Configuration is intentional or was a typo? For example, in your first block of code, you define the statement as such:

    if $(Configuration) == Debug2017 goto 2017 (where “Debug2017″ is the Debug option name).
    However right below it when you break it down, you refer it as:
    “if $(Configuration) == 2017 goto 2017”
    and continuing on into your last block of code you continue to reference it as:
    Condition=”‘$(Configuration)’ == ‘2017’”

    Why has Debug2017 changed to just 2017 in some cases?

    • They are just names. Yes, in my first block of code I must have used a Debug Configuration called “Debug2017” but later I must have had one called “2017”. I actually used to have one for Debug and one for Release. Debug2017 was my debug configuration and 2017 was my Release configuration. You can name your configuration whatever you want to.

  17. Liz Fong says:

    Awesome post! Thank you for sharing!

  18. Thanks for share Konrad. Always very important and usefull content.

    I’m trying to simplify Revit References in csproj file and this works (attached image).

    Revit 2022
    Revit 2021
    Revit 2020

    C:\Program Files\Autodesk\$(RevitVersion)\RevitAPI.dll
    False
    False

    C:\Program Files\Autodesk\$(RevitVersion)\RevitAPIUI.dll
    False
    False

    C:\Program Files\Autodesk\$(RevitVersion)\RevitAPIIFC.dll
    False
    False

    Add more Revit versions as you need.

Reply to Deyan Cancel Reply