|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Collections.Generic;
#if FEATURE_VISUALSTUDIOSETUP
using System.Runtime.InteropServices;
using Microsoft.VisualStudio.Setup.Configuration;
#endif
#nullable disable
namespace Microsoft.Build.Shared
{
/// <summary>
/// Helper class to wrap the Microsoft.VisualStudio.Setup.Configuration.Interop API to query
/// Visual Studio setup for instances installed on the machine.
/// Code derived from sample: https://code.msdn.microsoft.com/Visual-Studio-Setup-0cedd331
/// </summary>
internal class VisualStudioLocationHelper
{
#if FEATURE_VISUALSTUDIOSETUP
private const int REGDB_E_CLASSNOTREG = unchecked((int)0x80040154);
#endif // FEATURE_VISUALSTUDIOSETUP
/// <summary>
/// Query the Visual Studio setup API to get instances of Visual Studio installed
/// on the machine. Will not include anything before Visual Studio "15".
/// </summary>
/// <returns>Enumerable list of Visual Studio instances</returns>
internal static IList<VisualStudioInstance> GetInstances()
{
var validInstances = new List<VisualStudioInstance>();
#if FEATURE_VISUALSTUDIOSETUP
try
{
// This code is not obvious. See the sample (link above) for reference.
var query = (ISetupConfiguration2)GetQuery();
var e = query.EnumAllInstances();
int fetched;
var instances = new ISetupInstance[1];
do
{
// Call e.Next to query for the next instance (single item or nothing returned).
e.Next(1, instances, out fetched);
if (fetched <= 0)
{
continue;
}
var instance = instances[0];
var state = ((ISetupInstance2)instance).GetState();
Version version;
try
{
version = new Version(instance.GetInstallationVersion());
}
catch (FormatException)
{
continue;
}
// If the install was complete and a valid version, consider it.
if (state == InstanceState.Complete)
{
validInstances.Add(new VisualStudioInstance(
instance.GetDisplayName(),
instance.GetInstallationPath(),
version));
}
} while (fetched > 0);
}
catch (COMException)
{ }
catch (DllNotFoundException)
{
// This is OK, VS "15" or greater likely not installed.
}
#endif
return validInstances;
}
#if FEATURE_VISUALSTUDIOSETUP
private static ISetupConfiguration GetQuery()
{
try
{
// Try to CoCreate the class object.
return new SetupConfiguration();
}
catch (COMException ex) when (ex.ErrorCode == REGDB_E_CLASSNOTREG)
{
// Try to get the class object using app-local call.
ISetupConfiguration query;
var result = GetSetupConfiguration(out query, IntPtr.Zero);
if (result < 0)
{
throw new COMException("Failed to get query", result);
}
return query;
}
}
[DllImport("Microsoft.VisualStudio.Setup.Configuration.Native.dll", ExactSpelling = true, PreserveSig = true)]
private static extern int GetSetupConfiguration(
[MarshalAs(UnmanagedType.Interface), Out] out ISetupConfiguration configuration,
IntPtr reserved);
#endif
}
/// <summary>
/// Wrapper class to represent an installed instance of Visual Studio.
/// </summary>
internal class VisualStudioInstance
{
/// <summary>
/// Version of the Visual Studio Instance
/// </summary>
internal Version Version { get; }
/// <summary>
/// Path to the Visual Studio installation
/// </summary>
internal string Path { get; }
/// <summary>
/// Full name of the Visual Studio instance with SKU name
/// </summary>
internal string Name { get; }
internal VisualStudioInstance(string name, string path, Version version)
{
Name = name;
Path = path;
Version = version;
}
}
}
|