public override string GetVsVersion() { if (string.IsNullOrEmpty(_vsProductVersion)) { ISetupConfiguration configuration = new SetupConfiguration() as ISetupConfiguration; ISetupInstance instance = configuration.GetInstanceForCurrentProcess(); _vsProductVersion = instance.GetInstallationVersion(); } return(_vsProductVersion); }
public override string GetVsVersionAndInstance() { if (string.IsNullOrEmpty(_vsVersionInstance)) { ISetupConfiguration configuration = new SetupConfiguration() as ISetupConfiguration; ISetupInstance instance = configuration.GetInstanceForCurrentProcess(); string version = instance.GetInstallationVersion(); string instanceId = instance.GetInstanceId(); _vsVersionInstance = $"{version}-{instanceId}"; } return(_vsVersionInstance); }
private static void PrintInstance(ISetupInstance instance, ISetupHelper helper) { var instance2 = (ISetupInstance2)instance; var state = instance2.GetState(); Console.WriteLine($"InstanceId: {instance2.GetInstanceId()} ({(state == InstanceState.Complete ? "Complete" : "Incomplete")})"); var installationVersion = instance.GetInstallationVersion(); var version = helper.ParseVersion(installationVersion); Console.WriteLine($"InstallationVersion: {installationVersion} ({version})"); if ((state & InstanceState.Local) == InstanceState.Local) { Console.WriteLine($"InstallationPath: {instance2.GetInstallationPath()}"); } var catalog = instance as ISetupInstanceCatalog; if (catalog != null) { Console.WriteLine($"IsPrerelease: {catalog.IsPrerelease()}"); } if ((state & InstanceState.Registered) == InstanceState.Registered) { Console.WriteLine($"Product: {instance2.GetProduct().GetId()}"); Console.WriteLine("Workloads:"); PrintWorkloads(instance2.GetPackages()); } var properties = instance2.GetProperties(); if (properties != null) { Console.WriteLine("Custom properties:"); PrintProperties(properties); } properties = catalog?.GetCatalogInfo(); if (properties != null) { Console.WriteLine("Catalog properties:"); PrintProperties(properties); } Console.WriteLine(); }
/// <summary> /// Uses the VS SetupConfiguration COM API to resolve a path to a version-specific executable like DevEnv.exe or MSBuild.exe. /// </summary> /// <param name="buildVersionPath">Used to build a version-specific path to try to resolve.</param> /// <param name="minMajorVersion">The minimum major version to look for. This defaults to <see cref="VS2017MajorVersion"/>.</param> /// <param name="maxMajorVersion">The maximum major version to look for. This defaults to <see cref="int.MaxValue"/>.</param> /// <param name="resolvedPathMustExist">Whether the resolved version-specific path must exist. This defaults to false.</param> /// <returns>The resolved path for the highest matched version or null if no version was matched.</returns> public static string?ResolvePath( Func <Version, string> buildVersionPath, int minMajorVersion = VS2017MajorVersion, int maxMajorVersion = int.MaxValue, bool resolvedPathMustExist = false) { string? result = null; Version?resultVersion = null; // VS 2017 and up allow multiple side-by-side editions to be installed, and we have to use a COM API to enumerate the installed instances. // https://github.com/mluparu/vs-setup-samples - COM API samples // https://code.msdn.microsoft.com/Visual-Studio-Setup-0cedd331 - More Q&A about the COM API samples // https://blogs.msdn.microsoft.com/vcblog/2017/03/06/finding-the-visual-c-compiler-tools-in-visual-studio-2017/#comment-273625 // https://github.com/Microsoft/vswhere - A redistributable .exe for enumerating the VS instances from the command line. // https://blogs.msdn.microsoft.com/heaths/2016/09/15/changes-to-visual-studio-15-setup/ const int REGDB_E_CLASSNOTREG = -2147221164; // 0x80040154 try { // From MS example: https://github.com/Microsoft/vs-setup-samples/blob/master/Setup.Configuration.CS/Program.cs SetupConfiguration configuration = new(); IEnumSetupInstances instanceEnumerator = configuration.EnumAllInstances(); int fetched; ISetupInstance[] instances = new ISetupInstance[1]; do { instanceEnumerator.Next(1, instances, out fetched); if (fetched > 0) { ISetupInstance instance = instances[0]; if (instance != null && Version.TryParse(instance.GetInstallationVersion(), out Version? version) && version.Major >= minMajorVersion && version.Major <= maxMajorVersion) { InstanceState state = ((ISetupInstance2)instance).GetState(); if (state == InstanceState.Complete) { string?versionPath = buildVersionPath?.Invoke(version); if (!string.IsNullOrEmpty(versionPath)) { string resolvedPath = instance.ResolvePath(versionPath); if ((resultVersion == null || resultVersion < version) && (!resolvedPathMustExist || File.Exists(resolvedPath) || Directory.Exists(resolvedPath))) { result = resolvedPath; resultVersion = version; // If we're looking for a single version, then we don't need to keep looking. if (minMajorVersion == maxMajorVersion) { break; } } } } } } }while (fetched > 0); } #pragma warning disable CC0004 // Catch block cannot be empty catch (COMException ex) when(ex.HResult == REGDB_E_CLASSNOTREG) { // The SetupConfiguration API is not registered, so assume no instances are installed. } catch (Exception) { // Heath Stewart (MSFT), the author of the SetupConfiguration API, says to treat any exception as "no instances installed." // https://code.msdn.microsoft.com/windowsdesktop/Visual-Studio-Setup-0cedd331/view/Discussions#content } #pragma warning restore CC0004 // Catch block cannot be empty return(result); }