Skip to content

Commit 91b1bd9

Browse files
authored
Get MSBuild path from VS Setup API (#25)
1 parent cd7319a commit 91b1bd9

File tree

3 files changed

+72
-9
lines changed

3 files changed

+72
-9
lines changed

Packages.props

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
<ItemGroup>
44
<PackageReference Update="Microsoft.Build" Version="15.7.179" />
55
<PackageReference Update="Microsoft.NET.Test.Sdk" Version="15.7.2" />
6+
<PackageReference Update="Microsoft.VisualStudio.Setup.Configuration.Interop" Version="1.16.30" />
67
<PackageReference Update="MSTest.TestAdapter" Version="1.1.18" />
78
<PackageReference Update="MSTest.TestFramework" Version="1.1.18" />
89
<PackageReference Update="Shouldly" Version="3.0.0" />

src/MSBuildProjectCreator/MSBuildAssemblyResolver.cs

Lines changed: 70 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,11 @@
44

55
using System;
66
using System.IO;
7+
using System.Linq;
78
using System.Reflection;
9+
#if NET46
10+
using Microsoft.VisualStudio.Setup.Configuration;
11+
#endif
812

913
namespace Microsoft.Build.Utilities.ProjectCreation
1014
{
@@ -17,21 +21,15 @@ public static class MSBuildAssemblyResolver
1721
() =>
1822
{
1923
string visualStudioDirectory;
20-
string msbuildVersionDirectory = Environment.GetEnvironmentVariable("VISUALSTUDIOVERSION") ?? "15.0";
21-
22-
if (Version.TryParse(msbuildVersionDirectory, out Version visualStudioVersion) && visualStudioVersion.Major >= 16)
23-
{
24-
msbuildVersionDirectory = "Current";
25-
}
2624

2725
if (!String.IsNullOrWhiteSpace(visualStudioDirectory = Environment.GetEnvironmentVariable("VSINSTALLDIR")))
2826
{
29-
return Path.Combine(visualStudioDirectory, "MSBuild", msbuildVersionDirectory, "Bin");
27+
return Path.Combine(visualStudioDirectory, "MSBuild", GetMSBuildVersionDirectory(Environment.GetEnvironmentVariable("VISUALSTUDIOVERSION") ?? "15.0"), "Bin");
3028
}
3129

3230
if (!String.IsNullOrWhiteSpace(visualStudioDirectory = Environment.GetEnvironmentVariable("VSAPPIDDIR")))
3331
{
34-
return Path.GetFullPath(Path.Combine(visualStudioDirectory, "..", "..", "MSBuild", msbuildVersionDirectory, "Bin"));
32+
return Path.GetFullPath(Path.Combine(visualStudioDirectory, "..", "..", "MSBuild", GetMSBuildVersionDirectory(Environment.GetEnvironmentVariable("VISUALSTUDIOVERSION") ?? "15.0"), "Bin"));
3533
}
3634

3735
foreach (string path in (Environment.GetEnvironmentVariable("PATH") ?? String.Empty).Split(PathSplitChars, StringSplitOptions.RemoveEmptyEntries))
@@ -41,7 +39,12 @@ public static class MSBuildAssemblyResolver
4139
return path;
4240
}
4341
}
44-
42+
#if NET46
43+
if (!String.IsNullOrWhiteSpace(visualStudioDirectory = MSBuildAssemblyResolver.GetPathOfFirstInstalledVisualStudioInstance()))
44+
{
45+
return visualStudioDirectory;
46+
}
47+
#endif
4548
return null;
4649
},
4750
isThreadSafe: true);
@@ -63,6 +66,11 @@ public static Assembly AssemblyResolve(object sender, ResolveEventArgs args)
6366
{
6467
AssemblyName assemblyName = new AssemblyName(args.Name);
6568

69+
if (MSBuildPath == null)
70+
{
71+
return null;
72+
}
73+
6674
FileInfo fileInfo = new FileInfo(Path.Combine(MSBuildPath, $"{assemblyName.Name}.dll"));
6775

6876
if (!fileInfo.Exists)
@@ -72,5 +80,58 @@ public static Assembly AssemblyResolve(object sender, ResolveEventArgs args)
7280

7381
return !assemblyName.FullName.Equals(AssemblyName.GetAssemblyName(fileInfo.FullName).FullName) ? null : Assembly.LoadFrom(fileInfo.FullName);
7482
}
83+
84+
private static string GetMSBuildVersionDirectory(string version)
85+
{
86+
if (Version.TryParse(version, out Version visualStudioVersion) && visualStudioVersion.Major >= 16)
87+
{
88+
return "Current";
89+
}
90+
91+
return version;
92+
}
93+
94+
#if NET46
95+
private static string GetPathOfFirstInstalledVisualStudioInstance()
96+
{
97+
Tuple<Version, string> highestVersion = null;
98+
99+
try
100+
{
101+
IEnumSetupInstances setupInstances = new SetupConfiguration().EnumAllInstances();
102+
103+
ISetupInstance[] instances = new ISetupInstance[1];
104+
105+
for (setupInstances.Next(1, instances, out int fetched); fetched > 0; setupInstances.Next(1, instances, out fetched))
106+
{
107+
ISetupInstance2 instance = (ISetupInstance2)instances.First();
108+
109+
if (instance.GetState() == InstanceState.Complete)
110+
{
111+
string installationPath = instance.GetInstallationPath();
112+
113+
if (!String.IsNullOrWhiteSpace(installationPath) && Version.TryParse(instance.GetInstallationVersion(), out Version version))
114+
{
115+
if (highestVersion == null || version > highestVersion.Item1)
116+
{
117+
highestVersion = new Tuple<Version, string>(version, installationPath);
118+
}
119+
}
120+
}
121+
}
122+
123+
if (highestVersion != null)
124+
{
125+
return Path.Combine(highestVersion.Item2, "MSBuild", GetMSBuildVersionDirectory($"{highestVersion.Item1.Major}.{highestVersion.Item1.Minor}"), "Bin");
126+
}
127+
}
128+
catch
129+
{
130+
// Ignored
131+
}
132+
133+
return null;
134+
}
135+
#endif
75136
}
76137
}

src/MSBuildProjectCreator/MSBuildProjectCreator.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
<ItemGroup>
2323
<PackageReference Include="Microsoft.Build" ExcludeAssets="Runtime" />
24+
<PackageReference Include="Microsoft.VisualStudio.Setup.Configuration.Interop" Condition="'$(TargetFramework)' == 'net46'" />
2425

2526
<EmbeddedResource Update="Resources\Strings.resx">
2627
<Generator>ResXFileCodeGenerator</Generator>

0 commit comments

Comments
 (0)