Skip to content

Commit

Permalink
Use minimal powershell script to extract VS2017 location and versio…
Browse files Browse the repository at this point in the history
…n via COM*

Work with all flavors of VS2017, even the minimal "C++ Build Tools"
*https://blogs.msdn.microsoft.com/heaths/2016/09/15/changes-to-visual-studio-15-setup/
  • Loading branch information
refack committed Feb 6, 2017
1 parent ae96a08 commit d702483
Show file tree
Hide file tree
Showing 2 changed files with 206 additions and 116 deletions.
146 changes: 30 additions & 116 deletions lib/find-vs2017.js
Original file line number Diff line number Diff line change
@@ -1,138 +1,52 @@
module.exports = {
locateMsbuild: locateMsbuild,
locateVS2017: locateVS2017,
getVS2017WinSDKVersion: getVS2017WinSDKVersion,
setGypVS2017Env: setGypVS2017Env
}

var log = require('npmlog')
, fs = require('fs')
, path = require('path')
, cp = require('child_process')
, win = process.platform == 'win32'
, msgFormat = require('util').format
, findPython = require('./find-python')

var vs2017_install_path
, vs2017_win_sdk_ver

function run_locate(gyp, callback) {
if (!win) {
return callback(null, '', '')
}

if (vs2017_install_path || vs2017_install_path === '') {
return callback(null, vs2017_install_path, vs2017_win_sdk_ver)
}

var python = gyp.opts.python || process.env.PYTHON || 'python2'
, findvc_path = path.join(__dirname, '..', 'find_vs2017.py')

findPython(python, locate_vc);

function locate_vc(err, python_bin) {
if (err) {
return callback(err)
}

log.verbose('find vs2017', 'obtaining vs2017 install path using script %s',
findvc_path)
cp.execFile(python_bin, [findvc_path], function(err, stdout, stderr) {
if (err) {
return callback(err)
}
if (stdout) {
vs2017_install_path = stdout.split('\r\n')[0]
log.verbose('find vs2017', 'found Visual Studio 2017 in %s', vs2017_install_path)
get_sdk_version(python_bin)
} else {
log.verbose('find vs2017',
'no valid Visual Studio 2017 installation found')
vs2017_install_path = ''
vs2017_win_sdk_ver = ''
}
})
}

function get_sdk_version(python_bin) {
log.verbose('find vs2017', 'obtaining installed Windows SDKs')
cp.execFile(python_bin, [findvc_path, vs2017_install_path],
function(err, stdout, stderr) {
if (err) {
return callback(err)
}
if (stdout) {
vs2017_win_sdk_ver = stdout.split('\r\n')[0]
log.verbose('find vs2017', 'found VS2017 WinSDK %s', vs2017_win_sdk_ver)
} else {
log.verbose('find vs2017', 'no installed sdks found')
}

callback(null, vs2017_install_path, vs2017_win_sdk_ver)
})
var vs2017Setup

function tryVS7 (gyp) {
if (vs2017Setup) return vs2017Setup;
try {
const psFile = path.join(__dirname, '..', 'tools', 'Get-VSConfig.ps1');
const vsSetupRaw = cp.execSync('powershell ' + psFile).toString();
if (!vsSetupRaw) return;
const vsSetup = vsSetupRaw.split(/[\r|\n]/g).reduce((s, l) => {
const lParts = l.split(': ');
if (lParts.length > 1) s[lParts[0]] = lParts[1];
return s;
}, {});
return vs2017Setup = vsSetup;
} catch (e) {
gyp.log.verbose('try VS7', 'Couldn\'t find VS2017 :(');
}

}


function locateMsbuild(gyp, callback) {
run_locate(gyp, function(err, vs_path, sdk) {
if (err) {
return callback(err)
}
if (vs_path === '') {
return callback()
}
var msbuild_location = path.join(vs_path, 'MSBuild',
'15.0', 'Bin', 'MSBuild.exe')
log.verbose('find vs2017', 'looking for msbuild in %s', msbuild_location)
fs.access(msbuild_location, function(err) {
callback(null, err ? null : msbuild_location)
})
})
}
var vsSetup = tryVS7(gyp)
if (!vsSetup)return callback()

function locateVS2017(gyp, callback) {
run_locate(gyp, function(err, vs_path, sdk) {
if (err) {
callback(err)
} else {
callback(null, vs_path === '' ? null : vs_path)
}
var msbuild_location = path.join(vsSetup.InstallationPath, 'MSBuild',
'15.0', 'Bin', 'MSBuild.exe')
log.verbose('find vs2017', 'looking for msbuild in %s', msbuild_location)
fs.access(msbuild_location, function(err) {
callback(null, err ? null : msbuild_location)
})
}

function getVS2017WinSDKVersion(gyp, callback) {
run_locate(gyp, function(err, vs_path, sdk) {
if (err) {
callback(err)
} else {
callback(null, sdk === '' ? null : sdk)
}
})
}

function setGypVS2017Env(gyp, callback) {
locateVS2017(gyp, setPath)

function setPath(err, vs_path) {
if (err) {
return callback(err)
}
if (vs_path) {
process.env['vs2017_install'] = vs_path
getVS2017WinSDKVersion(gyp, setSDK)
} else {
callback()
}
}
var vsSetup = tryVS7(gyp);
if (!vsSetup)return callback()

function setSDK(err, sdk) {
if (err) {
return callback(err)
}
if (sdk) {
process.env['vs2017_sdk'] = sdk
}
callback()
}
gyp.opts.msvs_version = '2017';
process.env['vs2017_install'] = vsSetup.InstallationPath;
process.env['vs2017_sdk'] = vsSetup.SDK.replace(/\d+$/, '0')
callback();
}
176 changes: 176 additions & 0 deletions tools/Get-VSConfig.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
$Source = @"
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Microsoft.VisualStudio.Setup.Configuration;
namespace Microsoft.VisualStudio.Setup.Configuration
{
[CompilerGenerated]
[Flags]
[TypeIdentifier("310100ba-5f84-4103-abe0-e8132ae862d9", "Microsoft.VisualStudio.Setup.Configuration.InstanceState")]
[ComVisible(true)]
public enum InstanceState : uint
{
None = 0,
Local = 1,
Registered = 2,
NoRebootRequired = 4,
NoErrors = 8,
Complete = 4294967295
}
[CompilerGenerated]
[Guid("6380BCFF-41D3-4B2E-8B2E-BF8A6810C848")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[TypeIdentifier]
[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);
}
[CompilerGenerated]
[Guid("42843719-DB4C-46C2-8E7C-64F1816EFD5B")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[TypeIdentifier]
[ComImport]
public interface ISetupConfiguration
{
}
[CompilerGenerated]
[Guid("26AAB78C-4A60-49D6-AF3B-3C35BC93365D")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[TypeIdentifier]
[ComImport]
public interface ISetupConfiguration2 : ISetupConfiguration
{
[SpecialName]
[MethodImpl(MethodCodeType = MethodCodeType.Runtime)]
void _VtblGap1_3();
[return: MarshalAs(UnmanagedType.Interface)]
IEnumSetupInstances EnumAllInstances();
}
[CompilerGenerated]
[Guid("B41463C3-8866-43B5-BC33-2B0676F7F42E")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[TypeIdentifier]
[ComImport]
public interface ISetupInstance
{
[SpecialName]
[MethodImpl(MethodCodeType = MethodCodeType.Runtime)]
void _VtblGap1_4();
[return: MarshalAs(UnmanagedType.BStr)]
string GetInstallationVersion();
}
[CompilerGenerated]
[Guid("89143C9A-05AF-49B0-B717-72E218A2185C")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[TypeIdentifier]
[ComImport]
public interface ISetupInstance2 : ISetupInstance
{
[return: MarshalAs(UnmanagedType.BStr)]
string GetInstanceId();
[SpecialName]
[MethodImpl(MethodCodeType = MethodCodeType.Runtime)]
void _VtblGap1_2();
[return: MarshalAs(UnmanagedType.BStr)]
string GetInstallationPath();
[SpecialName]
[MethodImpl(MethodCodeType = MethodCodeType.Runtime)]
void _VtblGap2_4();
[return: MarshalAs(UnmanagedType.U4)]
InstanceState GetState();
[return: MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_UNKNOWN)]
ISetupPackageReference[] GetPackages();
ISetupPackageReference GetProduct();
}
[CompilerGenerated]
[Guid("DA8D8A16-B2B6-4487-A2F1-594CCCCD6BF5")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[TypeIdentifier]
[ComImport]
public interface ISetupPackageReference
{
[return: MarshalAs(UnmanagedType.BStr)]
string GetId();
[SpecialName]
[MethodImpl(MethodCodeType = MethodCodeType.Runtime)]
void _VtblGap1_4();
[return: MarshalAs(UnmanagedType.BStr)]
string GetType();
}
}
public static class VisualStudioSetup
{
public static int Main()
{
try
{
var query =
(ISetupConfiguration2)
Activator.CreateInstance(Marshal.GetTypeFromCLSID(new Guid("177F0C4A-1CD3-4DE7-A32C-71DBBB9FA36D")));
var enumSetupInstances = query.EnumAllInstances();
var rgelt = new ISetupInstance2[1];
int pceltFetched;
do
{
// ISSUE: reference to a compiler-generated method
enumSetupInstances.Next(1, rgelt, out pceltFetched);
if (pceltFetched > 0)
PrintInstance(rgelt[0]);
} while (pceltFetched > 0);
return 0;
}
catch (Exception ex)
{
Console.Error.WriteLine("Error 0x{0:x8}: {1}", ex.HResult, ex.Message);
return ex.HResult;
}
}
private static void PrintInstance(ISetupInstance2 setupInstance2)
{
Console.WriteLine("InstallationPath: {0}", setupInstance2.GetInstallationPath());
Console.WriteLine("Product: {0}", setupInstance2.GetProduct().GetId());
foreach (var package in setupInstance2.GetPackages())
{
if (package.GetType() != "Exe") continue;;
var id = package.GetId();
if (id.IndexOf("SDK", StringComparison.Ordinal) == -1) continue;
var parts = id.Split('_');
if (parts.Length < 2) continue;
var sdkVer = parts[1];
char[] chars = { '1', '0', '8' };
if (sdkVer.IndexOfAny(chars) == -1) continue;
Console.WriteLine("SDK: {0}", sdkVer);
}
Console.WriteLine();
}
}
"@
Add-Type -TypeDefinition $Source -Language CSharp
[VisualStudioSetup]::Main()

0 comments on commit d702483

Please sign in to comment.