Visual Studio extensions and version ranges demystified
Extension authors use visual Studio version ranges to specify what versions of Visual Studio their extensions support. A version range looks like this [14.0, 17.0) and specifies the minimum and maximum version of Visual Studio as well as if the edges are included or excluded. The syntax with mismatching braces may initially seem a bit odd and what exactly do those numbers refer to? Let’s unravel the mystery of the Visual Studio version ranges.
Let’s start by separating the version of Visual Studio from its name which can be a bit confusing. The 10th version of Visual Studio was released in the year 2010 and was given the name Visual Studio 2010. The fact that version 10.0 of Visual Studio was released in 2010 was coincidental, and made it seem like the version number followed the year of its release and therefore its name. Here’s a list of versions and names to illustrate how coincidental it was:
|8.0||Visual Studio 2005|
|9.0||Visual Studio 2008|
|10.0||Visual Studio 2010|
|11.0||Visual Studio 2012|
|12.0||Visual Studio 2013|
|14.0||Visual Studio 2015|
|15.0||Visual Studio 2017|
|16.0||Visual Studio 2019|
If Visual Studio continues to follow a release cadence of roughly every 2 years, then there will never again be a version that matches its name. Version 113.0 in the year 2213 will be the closest match.
You may be wondering why version 13.0 was skipped or attribute it to being an unlucky number in some cultures. That’s what I always thought, but then I started asking around and it turns out I was wrong. The real reason for skipping 13.0 was the believe that it would be confused with Visual Studio 2013 which was the current latest version at the time. Whether or not it made things less confusing in the end is up to you to decide.
In an extension that supports version 14.0, 15.0 and 16.0 of Visual Studio, express the version range like this [14.0, 17.0). Let’s break it down into its subparts.
It starts with a square bracket meaning edge inclusive which is then followed by 14.0. Let’s call this the from-part of the version range. You can read it like from and including version 14.0.
The last part is called the to-part and consists of the version number 17.0 followed by a parenthesis. A parenthesis means edge exclusive and will therefore not include the 17.0 version number. It can be read like up to, but not including version 17.0.
The entire version range [14.0, 17.0) therefore means from, and including version 14.0 – up to, but not including version 17.0. This version range syntax was introduced in Visual Studio 2015 (version 14.0).
Updates and minor versions
When an update to Visual Studio 2017 is shipped, it maintains its major and minor version, but the build and revision numbers change.
For instance, the full version of Visual Studio 2017 version 15.1 was 15.0.26403.0. Get the version numbers from this full list of Visual Studio versions and replace the minor version with 0 if you need to use it in an extension’s version range.
An extension can use an API introduced in version 15.1 but should make sure it can’t be installed on older versions to avoid runtime errors. To do that, the version range must reflect the build number of version 15.1 and could look like [15.0.26403, 17.0).
Visual Studio 2019
Why not just write 15.1 instead of 15.0.26403? In Visual Studio 2017 and earlier, this was due to an implementation detail and we therefore had to keep a 0 as the minor version and write out the long build number. In Visual Studio 2019 we can finally start using the minor version and forget about the build number. As of this writing, the are no updates released for Visual Studio 2019, but we will be able to write version ranges like [16.1, 17.0).
Let’s imagine that I wrote an extension with a feature that users have been asking the Visual Studio team to build into the official product. Finally, they release the feature as part of an update to Visual Studio 2019. Now I must make sure my extension cannot be installed in that version to avoid the two similar features from colliding. To do that, I would update the version range to be something like [14.0, 16.1) to express that from version 16.1 and beyond the extension isn’t supported.
Since minor version numbers are supported in version ranges in Visual Studio 2019, it means that the old syntax for specifying versions should no longer be used. The old syntax was one that didn’t have both a from and a to-part and was a simple version string like 16.0. That syntax is now interpreted as only version 16.0 by Visual Studio 2019 and doesn’t include any future updates such as 16.1.
To correctly specify a version range supporting version 16.0 including all its updates, the version range to use is [16.0, 17.0).
What if you want to specify that an extension should be supported by version 14.0 and all version of Visual Studio that will ever be released after that? Express that by omitting the to-part like [14.0,) which is known as an open-ended version range. However, we strongly discourage using open-ended versioning since it is considered a bad practice. In fact, soon you won’t be able to upload extensions with open-ended version ranges to the Marketplace.
There is no way of knowing that an extension will work in all future versions of Visual Studio. It probably won’t and will eventually cause a runtime error in that future version. Where open-ended version ranges are useful is when specifying dependencies and prerequisites. If my extension supports [15.0, 17.0) and has a dependency on a component that exist in all versions, then it makes good sense to write something like this in the .vsixmanifest file:
<Prerequisite Id="Microsoft.VisualStudio.Component.CoreEditor" Version="[15.0,)" />
What version to support
In a perfect world, an extension would only support the very latest release of Visual Studio to take advantage of the latest and greatest APIs. Unfortunately, not all Visual Studio users update to the latest version as soon as it is released. It is also easier to code, test and maintain extensions targeting as few versions of Visual Studio as possible.
So how many versions back does it make sense to support? What is the right balance of ease of coding and reaching as many potential users as possible?
To answer that question, we need to know the distribution of extension users using each version of Visual Studio. Today, over 95% of all extension users are on Visual Studio 2015 (14.0) or newer. So, if I were to write an extension today, I would target [14.0, 17.0).
I hope this helped clear up how the versioning works. If not, let me know in the comments.
This is helpful, thank you! I really appreciate how there is a lot more information to be found as an extension author these days compared to the VS2005 days. 🙂
Mads, Thanks for the info, but I have this error if I do all the actions from the post:
It’s not possible to install because there is no following links: Microsoft.VisualStudio.Component.CoreEditor.
The updated extension.vsixmanifest is:
<?xml version=”1.0″ encoding=”utf-8″?><PackageManifest Version=”2.0.0″ xmlns=”http://schemas.microsoft.com/developer/vsx-schema/2011″> <Metadata> <Identity Id=”PowerQuerySDK.Microsoft.30831070-f420-4649-a031-6f679996b182″ Version=”184.108.40.206″ Language=”en-US” Publisher=”Microsoft” /> <DisplayName>Power Query SDK</DisplayName> <Description xml:space=”preserve”>A Power Query language service for Visual Studio</Description> <License>Microsoft Power Query SDK – Pre-Release or Evaluation Use Terms.rtf</License> <Icon>dataconnector_128.png</Icon> <PreviewImage>EATIcon.ico</PreviewImage> </Metadata> <Installation> <InstallationTarget Id=”Microsoft.VisualStudio.Community” Version=”[14.0,17.0)” /> <InstallationTarget Version=”[14.0,17.0)” Id=”Microsoft.VisualStudio.Pro” /> <InstallationTarget Version=”[14.0,17.0)” Id=”Microsoft.VisualStudio.Enterprise” /> </Installation> <Dependencies> <Dependency Id=”Microsoft.Framework.NDP” DisplayName=”Microsoft .NET Framework” Version=”[4.5,)” /> </Dependencies> <Assets> <Asset Type=”Microsoft.VisualStudio.ProjectTemplate” Path=”ProjectTemplates” /> <Asset Type=”Microsoft.VisualStudio.ItemTemplate” Path=”ProjectTemplates” /> <Asset Type=”Microsoft.VisualStudio.VsPackage” Path=”Dependencies\Microsoft.Mashup.Tools.VisualStudio.pkgdef” /> <Asset Type=”Microsoft.VisualStudio.MefComponent” Path=”Dependencies\Microsoft.Mashup.Tools.VisualStudio.dll” /> </Assets> <Prerequisites> <Prerequisite Id=”Microsoft.VisualStudio.Component.CoreEditor” Version=”[15.0,)” DisplayName=”Visual Studio core editor” /> </Prerequisites></PackageManifest>
Please could you suggest what may be the problem?
Wouldn’t it be better (as long as it is feasible) if VS extensions where depended on features that should be present in VS instead of being depended on VS versions?So extension developers would declare that Extentions A depends on the presence of Feature A, Feature B and Feature C, and each VS version would declare that it provides Features A, B, C, D … etc.
It would be nice if it was that simple, but unfortunately it isn’t. That’s because the APIs keep evolving with each version of Visual Studio, so it’s important to specify which version you are depending on. You might use a new API that is only available in 16.0. If that extension is run in 15.0 then you are going to get exceptions that could lead to crashes or other bad things.
Always thorough, Mads. Thanks.
What are the possible values for InstallationTarget -> Id, and their meanings? It seems the docs articles (https://docs.microsoft.com/en-us/visualstudio/extensibility/vsix-extension-schema-2-0-reference?view=vs-2019#installation-element) are not updated to include the Community versions.
That is a great question. One and it deserves its own blog post, because that is actually not easy to answer in a comment. The list of values are changing with each version of Visual Studio – some are added and some removed. I’ll add it to my blogging backlog
I found my problem I described earlier in comments here. It worth to mention that you shoud check file catalog.json inside the extension installation file, in addition to extension.vsixmanifest.There was mention of CoreEditor with the old version numbers in the extension, so I could not install extension until I changed file catalog.json appropriately.
I’m glad you solved it. Yes, catalog.json needs to be updated as well if you do a upgrade by directly modifying the .vsix container files.
> The real reason for skipping 13.0 was the believe that it would be confused with Visual Studio 2013 which was the current latest version at the time.
I don’t really think it was the reason. There was Visual Studio 2012 and right after it VS2013 version 12.0. You could say that version 13.0 was later and they took into account some problems with 12.0, but then there was Visual Studio 2015 and right after it VS2017 version 15.0. So I don’t think that exactly Visual Studio 2013 was the one and the only not to be confused with the next version number.
I asked a person who was in the meeting when it was decided.
I thought the exact same thing as you @alexander ovchinnikov
Thanks for all the details. Will dte.Version remain 16.0.xxx or can we expect 16.1 16.2 … ? With VS 2017 it is still 15.0.xxx even for 15.9.3 for example
The EnvDTE.Version property will report only the major version (“16.0”) regardless of any updates installed – just like with previous versions.
Can we expect some 16.1, 16.2 … in the context of registry keys like HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\16.0 (or any regkey like HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\DevDiv\vs\Servicing\16.0)
Registry keys will stay 16.0. However, with the move to the private registry hives (privateregistry.bin), user should no longer try to access the non-private Visual Studio registry keys directly since they are implementation details, can be changed without notice, and/or might be removed.
Thanks Mads, still quite useful to access the private registry hives for info like themeId or MRU VS files paths.
Can we expect some 16.1, 16.2 … in the context of folders like C:\Users\(user)\AppData\Local\Microsoft\VisualStudio\16.0
or any path under C:\Program Files (x86)\Microsoft Visual Studio that might contain 16.0 like
C:\Program Files (x86)\Microsoft Visual Studio\2019\Preview\MSBuild\Microsoft\NuGet\16.0
C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\MSBuild\15.0
C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\MSBuild\Microsoft\NuGet\15.0
C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\Common7\IDE\Extensions\Microsoft\Modeling\15.0
Can we expect some 16.1, 16.2 … in the context of VSIXInstaller.exe /skuVersion:16.0 …
No, the /skuVersion will remain 16.0 for extensions targeting 16.0
Can we expect some 16.1, 16.2 … in the context of VS dll names like Microsoft.VisualStudio.Debugger.Interop.16.0.dll System.Drawing.VisualStudio.15.0.dll
We usually only rev the version numbers in the file names once per major release otherwise references are broken. At this time I don’t know of any reason we’d need to rev the version in the file name until the next major VS release.
Can we expect some 16.1, 16.2 … in the context of VS solution file format like 16.0.28721.148 in
Microsoft Visual Studio Solution File, Format Version 12.00# Visual Studio Version 16VisualStudioVersion = 16.0.28721.148
I followed your articles to update the https://marketplace.visualstudio.com/items?itemName=LLVMExtensions.llvm-toolchain
I build it and installed it. My CMake project using Clang worked but unfortunately the LLVM toolchain didn’t appear in the MSBuild project property parges. I am unable to figure out from the documentation about adding custom toolchains if anything has been changed.