// Copyright (c) 2012-2020 Flax Engine. All rights reserved. using System; using System.Collections.Generic; using System.IO; using System.Linq; using Flax.Build.Platforms; using Microsoft.VisualStudio.Setup.Configuration; using Task = Flax.Build.Graph.Task; namespace Flax.Build.Projects.VisualStudio { /// /// The Visual Studio instance utility. /// public sealed class VisualStudioInstance { private static List _installDirs; private static int _hasFlaxVS; /// /// The version. /// public VisualStudioVersion Version; /// /// The install directory path. /// public string Path; /// /// Determinates whenever Visual Studio has Flax.VS extension installed (for C# scripts debugging). /// public static bool HasFlaxVS { get { if (_hasFlaxVS == 0) { var p = Profiling.Begin("HasFlaxVS"); // This doesn't do the best job but it can detect if user has installed Flax.VS to any Visual Studio and should be enough var appData = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Microsoft", "VisualStudio"); _hasFlaxVS = FindFlaxVS(appData) ? 1 : 2; Profiling.End(p); } return _hasFlaxVS == 1; } } private static bool FindFlaxVS(string path) { if (!Directory.Exists(path)) return false; var files = Directory.GetFiles(path); for (int i = 0; i < files.Length; i++) { if (files[i].EndsWith("Flax.VS.dll")) return true; } var folders = Directory.GetDirectories(path); for (int i = 0; i < folders.Length; i++) { if (FindFlaxVS(folders[i])) return true; } return false; } /// /// Determines whether any version of the IDE is installed. /// /// true if any version is installed; otherwise, false. public static bool HasIDE() { return GetInstances().Count != 0; } /// /// Determines whether the specified version of the IDE is installed. /// /// The version to check. /// true if the specified version is installed; otherwise, false. public static bool HasIDE(VisualStudioVersion version) { return GetInstances().Any(x => x.Version == version); } /// /// Gets the installed Visual Studio instances (the first item is the latest version). /// /// The install locations. public static IReadOnlyList GetInstances() { if (_installDirs != null) return _installDirs; _installDirs = new List(); // Skip if running on non-Windows system if (Platform.BuildTargetPlatform != TargetPlatform.Windows) return _installDirs; if (Environment.OSVersion.Platform == PlatformID.Win32NT) { // Visual Studio 2017-2022 List preReleaseInstallDirs = null; try { SetupConfiguration setup = new SetupConfiguration(); IEnumSetupInstances enumerator = setup.EnumAllInstances(); ISetupInstance[] instances = new ISetupInstance[1]; while (true) { enumerator.Next(1, instances, out int fetchedCount); if (fetchedCount == 0) break; ISetupInstance2 instance = (ISetupInstance2)instances[0]; if ((instance.GetState() & InstanceState.Local) == InstanceState.Local) { VisualStudioVersion version; string displayName = instance.GetDisplayName(); if (displayName.Contains("2017")) version = VisualStudioVersion.VisualStudio2017; else if (displayName.Contains("2019")) version = VisualStudioVersion.VisualStudio2019; else if (displayName.Contains("2022")) version = VisualStudioVersion.VisualStudio2022; else { Log.Warning(string.Format("Unknown Visual Studio installation. Display name: {0}", displayName)); continue; } var vsInstance = new VisualStudioInstance { Version = version, Path = instance.GetInstallationPath(), }; if (instance is ISetupInstanceCatalog catalog && catalog.IsPrerelease()) { if (preReleaseInstallDirs == null) preReleaseInstallDirs = new List(); preReleaseInstallDirs.Add(vsInstance); } else { _installDirs.Add(vsInstance); } } } } catch { // Ignore errors } // Add pre-release locations after the normal installations if (preReleaseInstallDirs != null) _installDirs.AddRange(preReleaseInstallDirs); // Visual Studio 2015 if (WindowsPlatform.TryReadInstallDirRegistryKey32("Microsoft\\VisualStudio\\SxS\\VS7", "14.0", out var dir)) { _installDirs.Add(new VisualStudioInstance { Version = VisualStudioVersion.VisualStudio2015, Path = dir, }); } } foreach (var e in _installDirs) Log.Verbose($"Found {e.Version} at {e.Path}"); return _installDirs; } } }