| // Copyright 2017 - Refael Ackermann |
| // Distributed under MIT style license |
| // See accompanying file LICENSE at https://github.com/node4good/windows-autoconf |
| |
| // Usage: |
| // powershell -ExecutionPolicy Unrestricted -Version "2.0" -Command "&{Add-Type -Path Find-VS2017.cs; [VisualStudioConfiguration.Main]::Query()}" |
| using System; |
| using System.Text; |
| using System.Runtime.InteropServices; |
| |
| namespace VisualStudioConfiguration |
| { |
| [Flags] |
| public enum InstanceState : uint |
| { |
| None = 0, |
| Local = 1, |
| Registered = 2, |
| NoRebootRequired = 4, |
| NoErrors = 8, |
| Complete = 4294967295, |
| } |
| |
| [Guid("6380BCFF-41D3-4B2E-8B2E-BF8A6810C848")] |
| [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] |
| [ComImport] |
| public interface IEnumSetupInstances |
| { |
| |
| void Next([MarshalAs(UnmanagedType.U4), In] int celt, |
| [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.Interface), Out] ISetupInstance[] rgelt, |
| [MarshalAs(UnmanagedType.U4)] out int pceltFetched); |
| |
| void Skip([MarshalAs(UnmanagedType.U4), In] int celt); |
| |
| void Reset(); |
| |
| [return: MarshalAs(UnmanagedType.Interface)] |
| IEnumSetupInstances Clone(); |
| } |
| |
| [Guid("42843719-DB4C-46C2-8E7C-64F1816EFD5B")] |
| [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] |
| [ComImport] |
| public interface ISetupConfiguration |
| { |
| } |
| |
| [Guid("26AAB78C-4A60-49D6-AF3B-3C35BC93365D")] |
| [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] |
| [ComImport] |
| public interface ISetupConfiguration2 : ISetupConfiguration |
| { |
| |
| [return: MarshalAs(UnmanagedType.Interface)] |
| IEnumSetupInstances EnumInstances(); |
| |
| [return: MarshalAs(UnmanagedType.Interface)] |
| ISetupInstance GetInstanceForCurrentProcess(); |
| |
| [return: MarshalAs(UnmanagedType.Interface)] |
| ISetupInstance GetInstanceForPath([MarshalAs(UnmanagedType.LPWStr), In] string path); |
| |
| [return: MarshalAs(UnmanagedType.Interface)] |
| IEnumSetupInstances EnumAllInstances(); |
| } |
| |
| [Guid("B41463C3-8866-43B5-BC33-2B0676F7F42E")] |
| [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] |
| [ComImport] |
| public interface ISetupInstance |
| { |
| } |
| |
| [Guid("89143C9A-05AF-49B0-B717-72E218A2185C")] |
| [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] |
| [ComImport] |
| public interface ISetupInstance2 : ISetupInstance |
| { |
| [return: MarshalAs(UnmanagedType.BStr)] |
| string GetInstanceId(); |
| |
| [return: MarshalAs(UnmanagedType.Struct)] |
| System.Runtime.InteropServices.ComTypes.FILETIME GetInstallDate(); |
| |
| [return: MarshalAs(UnmanagedType.BStr)] |
| string GetInstallationName(); |
| |
| [return: MarshalAs(UnmanagedType.BStr)] |
| string GetInstallationPath(); |
| |
| [return: MarshalAs(UnmanagedType.BStr)] |
| string GetInstallationVersion(); |
| |
| [return: MarshalAs(UnmanagedType.BStr)] |
| string GetDisplayName([MarshalAs(UnmanagedType.U4), In] int lcid); |
| |
| [return: MarshalAs(UnmanagedType.BStr)] |
| string GetDescription([MarshalAs(UnmanagedType.U4), In] int lcid); |
| |
| [return: MarshalAs(UnmanagedType.BStr)] |
| string ResolvePath([MarshalAs(UnmanagedType.LPWStr), In] string pwszRelativePath); |
| |
| [return: MarshalAs(UnmanagedType.U4)] |
| InstanceState GetState(); |
| |
| [return: MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_UNKNOWN)] |
| ISetupPackageReference[] GetPackages(); |
| |
| ISetupPackageReference GetProduct(); |
| |
| [return: MarshalAs(UnmanagedType.BStr)] |
| string GetProductPath(); |
| |
| [return: MarshalAs(UnmanagedType.VariantBool)] |
| bool IsLaunchable(); |
| |
| [return: MarshalAs(UnmanagedType.VariantBool)] |
| bool IsComplete(); |
| |
| [return: MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_UNKNOWN)] |
| ISetupPropertyStore GetProperties(); |
| |
| [return: MarshalAs(UnmanagedType.BStr)] |
| string GetEnginePath(); |
| } |
| |
| [Guid("DA8D8A16-B2B6-4487-A2F1-594CCCCD6BF5")] |
| [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] |
| [ComImport] |
| public interface ISetupPackageReference |
| { |
| |
| [return: MarshalAs(UnmanagedType.BStr)] |
| string GetId(); |
| |
| [return: MarshalAs(UnmanagedType.BStr)] |
| string GetVersion(); |
| |
| [return: MarshalAs(UnmanagedType.BStr)] |
| string GetChip(); |
| |
| [return: MarshalAs(UnmanagedType.BStr)] |
| string GetLanguage(); |
| |
| [return: MarshalAs(UnmanagedType.BStr)] |
| string GetBranch(); |
| |
| [return: MarshalAs(UnmanagedType.BStr)] |
| string GetType(); |
| |
| [return: MarshalAs(UnmanagedType.BStr)] |
| string GetUniqueId(); |
| |
| [return: MarshalAs(UnmanagedType.VariantBool)] |
| bool GetIsExtension(); |
| } |
| |
| [Guid("c601c175-a3be-44bc-91f6-4568d230fc83")] |
| [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] |
| [ComImport] |
| public interface ISetupPropertyStore |
| { |
| |
| [return: MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_BSTR)] |
| string[] GetNames(); |
| |
| object GetValue([MarshalAs(UnmanagedType.LPWStr), In] string pwszName); |
| } |
| |
| [Guid("42843719-DB4C-46C2-8E7C-64F1816EFD5B")] |
| [CoClass(typeof(SetupConfigurationClass))] |
| [ComImport] |
| public interface SetupConfiguration : ISetupConfiguration2, ISetupConfiguration |
| { |
| } |
| |
| [Guid("177F0C4A-1CD3-4DE7-A32C-71DBBB9FA36D")] |
| [ClassInterface(ClassInterfaceType.None)] |
| [ComImport] |
| public class SetupConfigurationClass |
| { |
| } |
| |
| public static class Main |
| { |
| public static void Query() |
| { |
| ISetupConfiguration query = new SetupConfiguration(); |
| ISetupConfiguration2 query2 = (ISetupConfiguration2)query; |
| IEnumSetupInstances e = query2.EnumAllInstances(); |
| |
| int pceltFetched; |
| ISetupInstance2[] rgelt = new ISetupInstance2[1]; |
| StringBuilder log = new StringBuilder(); |
| while (true) |
| { |
| e.Next(1, rgelt, out pceltFetched); |
| if (pceltFetched <= 0) |
| { |
| Console.WriteLine(String.Format("{{\"log\":\"{0}\"}}", log.ToString())); |
| return; |
| } |
| if (CheckInstance(rgelt[0], ref log)) |
| return; |
| } |
| } |
| |
| private static bool CheckInstance(ISetupInstance2 setupInstance2, ref StringBuilder log) |
| { |
| // Visual Studio Community 2017 component directory: |
| // https://www.visualstudio.com/en-us/productinfo/vs2017-install-product-Community.workloads |
| |
| string path = setupInstance2.GetInstallationPath().Replace("\\", "\\\\"); |
| log.Append(String.Format("Found installation at: {0}\\n", path)); |
| |
| bool hasMSBuild = false; |
| bool hasVCTools = false; |
| uint Win10SDKVer = 0; |
| bool hasWin8SDK = false; |
| |
| foreach (ISetupPackageReference package in setupInstance2.GetPackages()) |
| { |
| const string Win10SDKPrefix = "Microsoft.VisualStudio.Component.Windows10SDK."; |
| |
| string id = package.GetId(); |
| if (id == "Microsoft.VisualStudio.VC.MSBuild.Base") |
| hasMSBuild = true; |
| else if (id == "Microsoft.VisualStudio.Component.VC.Tools.x86.x64") |
| hasVCTools = true; |
| else if (id.StartsWith(Win10SDKPrefix)) { |
| string[] parts = id.Substring(Win10SDKPrefix.Length).Split('.'); |
| if (parts.Length > 1 && parts[1] != "Desktop") |
| continue; |
| uint foundSdkVer; |
| if (UInt32.TryParse(parts[0], out foundSdkVer)) |
| Win10SDKVer = Math.Max(Win10SDKVer, foundSdkVer); |
| } else if (id == "Microsoft.VisualStudio.Component.Windows81SDK") |
| hasWin8SDK = true; |
| else |
| continue; |
| |
| log.Append(String.Format(" - Found {0}\\n", id)); |
| } |
| |
| if (!hasMSBuild) |
| log.Append(" - Missing Visual Studio C++ core features (Microsoft.VisualStudio.VC.MSBuild.Base)\\n"); |
| if (!hasVCTools) |
| log.Append(" - Missing VC++ 2017 v141 toolset (x86,x64) (Microsoft.VisualStudio.Component.VC.Tools.x86.x64)\\n"); |
| if ((Win10SDKVer == 0) && (!hasWin8SDK)) |
| log.Append(" - Missing a Windows SDK (Microsoft.VisualStudio.Component.Windows10SDK.* or Microsoft.VisualStudio.Component.Windows81SDK)\\n"); |
| |
| if (hasMSBuild && hasVCTools) |
| { |
| if (Win10SDKVer > 0) |
| { |
| log.Append(" - Using this installation with Windows 10 SDK"/*\\n*/); |
| Console.WriteLine(String.Format("{{\"log\":\"{0}\",\"path\":\"{1}\",\"sdk\":\"10.0.{2}.0\"}}", log.ToString(), path, Win10SDKVer)); |
| return true; |
| } |
| else if (hasWin8SDK) |
| { |
| log.Append(" - Using this installation with Windows 8.1 SDK"/*\\n*/); |
| Console.WriteLine(String.Format("{{\"log\":\"{0}\",\"path\":\"{1}\",\"sdk\":\"8.1\"}}", log.ToString(), path)); |
| return true; |
| } |
| } |
| |
| log.Append(" - Some required components are missing, not using this installation\\n"); |
| return false; |
| } |
| } |
| } |