77using System . Runtime . CompilerServices ;
88using System . Runtime . InteropServices ;
99using System . Runtime . InteropServices . Marshalling ;
10+ using System . Text ;
1011
1112namespace Microsoft . Build . Locator
1213{
@@ -25,17 +26,19 @@ private enum hostfxr_resolve_sdk2_result_key_t
2526 global_json_path = 1 ,
2627 } ;
2728
28- internal static int hostfxr_resolve_sdk2 ( string exe_dir , string working_dir , hostfxr_resolve_sdk2_flags_t flags , out string resolved_sdk_dir , out string global_json_path )
29+ internal static int hostfxr_resolve_sdk2 ( string exe_dir , string working_dir , hostfxr_resolve_sdk2_flags_t flags , out string resolved_sdk_dir , out string global_json_path , out StringBuilder errorMessage )
2930 {
3031 Debug . Assert ( t_resolve_sdk2_resolved_sdk_dir is null ) ;
3132 Debug . Assert ( t_resolve_sdk2_global_json_path is null ) ;
3233 try
3334 {
3435 unsafe
3536 {
37+ using var errorHandler = new ErrorHandler ( ) ;
3638 int result = hostfxr_resolve_sdk2 ( exe_dir , working_dir , flags , & hostfxr_resolve_sdk2_callback ) ;
3739 resolved_sdk_dir = t_resolve_sdk2_resolved_sdk_dir ;
3840 global_json_path = t_resolve_sdk2_global_json_path ;
41+ errorMessage = t_hostfxr_error_builder ;
3942 return result ;
4043 }
4144 }
@@ -72,15 +75,17 @@ private static unsafe void hostfxr_resolve_sdk2_callback(hostfxr_resolve_sdk2_re
7275 }
7376 }
7477
75- internal static int hostfxr_get_available_sdks ( string exe_dir , out string [ ] sdks )
78+ internal static int hostfxr_get_available_sdks ( string exe_dir , out string [ ] sdks , out StringBuilder errorMessage )
7679 {
7780 Debug . Assert ( t_get_available_sdks_result is null ) ;
7881 try
7982 {
8083 unsafe
8184 {
85+ using var errorHandler = new ErrorHandler ( ) ;
8286 int result = hostfxr_get_available_sdks ( exe_dir , & hostfxr_get_available_sdks_callback ) ;
8387 sdks = t_get_available_sdks_result ;
88+ errorMessage = t_hostfxr_error_builder ;
8489 return result ;
8590 }
8691 }
@@ -108,6 +113,29 @@ private static unsafe void hostfxr_get_available_sdks_callback(int count, void**
108113 t_get_available_sdks_result = result ;
109114 }
110115
116+ [ LibraryImport ( HostFxrName ) ]
117+ [ UnmanagedCallConv ( CallConvs = [ typeof ( CallConvCdecl ) ] ) ]
118+ private static unsafe partial delegate * unmanaged[ Cdecl] < void * , void > hostfxr_set_error_writer ( delegate * unmanaged[ Cdecl] < void * , void > error_writer ) ;
119+
120+ [ ThreadStatic ]
121+ private static StringBuilder t_hostfxr_error_builder ;
122+
123+ [ UnmanagedCallersOnly ( CallConvs = [ typeof ( CallConvCdecl ) ] ) ]
124+ private static unsafe void hostfxr_error_writer_callback ( void * message )
125+ {
126+ t_hostfxr_error_builder ??= new StringBuilder ( ) ;
127+ if ( OperatingSystem . IsWindows ( ) )
128+ {
129+ // Avoid allocating temporary string on Windows.
130+ t_hostfxr_error_builder . Append ( MemoryMarshal . CreateReadOnlySpanFromNullTerminated ( ( char * ) message ) ) ;
131+ t_hostfxr_error_builder . AppendLine ( ) ;
132+ }
133+ else
134+ {
135+ t_hostfxr_error_builder . AppendLine ( Utf8StringMarshaller . ConvertToManaged ( ( byte * ) message ) ) ;
136+ }
137+ }
138+
111139 [ CustomMarshaller ( typeof ( string ) , MarshalMode . Default , typeof ( AutoStringMarshaller ) ) ]
112140 internal static unsafe class AutoStringMarshaller
113141 {
@@ -117,6 +145,23 @@ internal static unsafe class AutoStringMarshaller
117145
118146 public static string ConvertToManaged ( void * ptr ) => Marshal . PtrToStringAuto ( ( nint ) ptr ) ;
119147 }
148+
149+ private unsafe readonly ref struct ErrorHandler
150+ {
151+ private readonly delegate * unmanaged[ Cdecl] < void * , void > _previousCallback ;
152+
153+ public ErrorHandler ( )
154+ {
155+ Debug . Assert ( t_hostfxr_error_builder is null ) ;
156+ _previousCallback = hostfxr_set_error_writer ( & hostfxr_error_writer_callback ) ;
157+ }
158+
159+ public void Dispose ( )
160+ {
161+ hostfxr_set_error_writer ( _previousCallback ) ;
162+ t_hostfxr_error_builder = null ;
163+ }
164+ }
120165 }
121166}
122167#endif
0 commit comments