33// Licensed under the MIT license.
44
55using System ;
6+ using System . Diagnostics ;
67using System . IO ;
8+ #if ! NETCORE
79using System . Linq ;
10+ #endif
811using System . Reflection ;
9- #if NET46
12+ using System . Text . RegularExpressions ;
13+ using System . Threading ;
14+ #if ! NETCORE
1015using Microsoft . VisualStudio . Setup . Configuration ;
1116#endif
1217
@@ -17,9 +22,26 @@ namespace Microsoft.Build.Utilities.ProjectCreation
1722 /// </summary>
1823 public static class MSBuildAssemblyResolver
1924 {
25+ #if NETCORE
26+ private static readonly Regex DotNetBasePathRegex = new Regex ( @"^ Base Path:\s+(?<Path>.*)$" ) ;
27+ #endif
28+
2029 private static readonly Lazy < string > MSBuildDirectoryLazy = new Lazy < string > (
2130 ( ) =>
2231 {
32+ #if NETCORE
33+ string basePath ;
34+
35+ if ( ! string . IsNullOrWhiteSpace ( basePath = GetDotNetBasePath ( ) ) )
36+ {
37+ return basePath ;
38+ }
39+
40+ if ( ! string . IsNullOrWhiteSpace ( basePath = Environment . GetEnvironmentVariable ( "MSBuildExtensionsPath" ) ) )
41+ {
42+ return basePath ;
43+ }
44+ #else
2345 string visualStudioDirectory ;
2446
2547 if ( ! string . IsNullOrWhiteSpace ( visualStudioDirectory = Environment . GetEnvironmentVariable ( "VSINSTALLDIR" ) ) )
@@ -39,7 +61,7 @@ public static class MSBuildAssemblyResolver
3961 return path ;
4062 }
4163 }
42- #if NET46
64+
4365 if ( ! string . IsNullOrWhiteSpace ( visualStudioDirectory = MSBuildAssemblyResolver . GetPathOfFirstInstalledVisualStudioInstance ( ) ) )
4466 {
4567 return visualStudioDirectory ;
@@ -81,6 +103,91 @@ public static Assembly AssemblyResolve(object sender, ResolveEventArgs args)
81103 return ! assemblyName . FullName . Equals ( AssemblyName . GetAssemblyName ( fileInfo . FullName ) . FullName ) ? null : Assembly . LoadFrom ( fileInfo . FullName ) ;
82104 }
83105
106+ #if NETCORE
107+
108+ private static string GetDotNetBasePath ( )
109+ {
110+ string basePath = null ;
111+
112+ using ( ManualResetEvent processExited = new ManualResetEvent ( false ) )
113+ using ( Process process = new Process
114+ {
115+ EnableRaisingEvents = true ,
116+ StartInfo = new ProcessStartInfo
117+ {
118+ Arguments = "--info" ,
119+ CreateNoWindow = true ,
120+ FileName = "dotnet" ,
121+ UseShellExecute = false ,
122+ RedirectStandardError = true ,
123+ RedirectStandardInput = true ,
124+ RedirectStandardOutput = true ,
125+ WorkingDirectory = Environment . CurrentDirectory ,
126+ } ,
127+ } )
128+ {
129+ process . StartInfo . EnvironmentVariables [ "DOTNET_CLI_UI_LANGUAGE" ] = "en-US" ;
130+
131+ process . ErrorDataReceived += ( sender , args ) => { } ;
132+
133+ process . OutputDataReceived += ( sender , args ) =>
134+ {
135+ if ( ! String . IsNullOrWhiteSpace ( args ? . Data ) )
136+ {
137+ Match match = DotNetBasePathRegex . Match ( args . Data ) ;
138+
139+ if ( match . Success && match . Groups [ "Path" ] . Success )
140+ {
141+ basePath = match . Groups [ "Path" ] . Value . Trim ( ) ;
142+ }
143+ }
144+ } ;
145+
146+ process . Exited += ( sender , args ) => { processExited . Set ( ) ; } ;
147+
148+ try
149+ {
150+ if ( ! process . Start ( ) )
151+ {
152+ return null ;
153+ }
154+ }
155+ catch
156+ {
157+ return null ;
158+ }
159+
160+ process . StandardInput . Close ( ) ;
161+
162+ process . BeginErrorReadLine ( ) ;
163+ process . BeginOutputReadLine ( ) ;
164+
165+ switch ( WaitHandle . WaitAny ( new WaitHandle [ ] { processExited } , TimeSpan . FromSeconds ( 5 ) ) )
166+ {
167+ case WaitHandle . WaitTimeout :
168+ break ;
169+
170+ case 0 :
171+ break ;
172+ }
173+
174+ if ( ! process . HasExited )
175+ {
176+ try
177+ {
178+ process . Kill ( ) ;
179+ }
180+ catch
181+ {
182+ }
183+ }
184+
185+ return basePath ;
186+ }
187+ }
188+
189+ #endif
190+
84191 private static string GetMSBuildVersionDirectory ( string version )
85192 {
86193 if ( Version . TryParse ( version , out Version visualStudioVersion ) && visualStudioVersion . Major >= 16 )
@@ -91,7 +198,7 @@ private static string GetMSBuildVersionDirectory(string version)
91198 return version ;
92199 }
93200
94- #if NET46
201+ #if ! NETCORE
95202 private static string GetPathOfFirstInstalledVisualStudioInstance ( )
96203 {
97204 Tuple < Version , string > highestVersion = null ;
0 commit comments