8
8
9
9
namespace HostApiInvokerApp
10
10
{
11
- public static class HostFXR
11
+ public static unsafe class HostFXR
12
12
{
13
13
internal static class hostfxr
14
14
{
@@ -59,6 +59,34 @@ internal struct hostfxr_dotnet_environment_info
59
59
internal IntPtr frameworks ;
60
60
}
61
61
62
+ [ StructLayout ( LayoutKind . Sequential , CharSet = CharSet . Auto ) ]
63
+ internal struct hostfxr_framework_result
64
+ {
65
+ public nuint size ;
66
+ public string name ;
67
+ public string requested_version ;
68
+ public string resolved_version ;
69
+ public string resolved_path ;
70
+ } ;
71
+
72
+ [ StructLayout ( LayoutKind . Sequential ) ]
73
+ internal struct hostfxr_resolve_frameworks_result
74
+ {
75
+ public nuint size ;
76
+ public nuint resolved_count ;
77
+ public IntPtr resolved_frameworks ;
78
+ public nuint unresolved_count ;
79
+ public IntPtr unresolved_frameworks ;
80
+ } ;
81
+
82
+ [ StructLayout ( LayoutKind . Sequential ) ]
83
+ internal struct hostfxr_initialize_parameters
84
+ {
85
+ public nuint size ;
86
+ public IntPtr host_path ;
87
+ public IntPtr dotnet_root ;
88
+ }
89
+
62
90
[ UnmanagedFunctionPointer ( CallingConvention . Cdecl , CharSet = CharSet . Auto ) ]
63
91
internal delegate void hostfxr_resolve_sdk2_result_fn (
64
92
hostfxr_resolve_sdk2_result_key_t key ,
@@ -101,6 +129,18 @@ internal static extern int hostfxr_get_dotnet_environment_info(
101
129
IntPtr reserved ,
102
130
hostfxr_get_dotnet_environment_info_result_fn result ,
103
131
IntPtr result_context ) ;
132
+
133
+ [ UnmanagedFunctionPointer ( CallingConvention . Cdecl ) ]
134
+ internal delegate void hostfxr_resolve_frameworks_result_fn (
135
+ IntPtr result ,
136
+ IntPtr result_context ) ;
137
+
138
+ [ DllImport ( nameof ( hostfxr ) , CharSet = CharSet . Auto , ExactSpelling = true , CallingConvention = CallingConvention . Cdecl ) ]
139
+ internal static extern int hostfxr_resolve_frameworks_for_runtime_config (
140
+ string runtime_config_path ,
141
+ hostfxr_initialize_parameters * parameters ,
142
+ hostfxr_resolve_frameworks_result_fn callback ,
143
+ IntPtr result_context ) ;
104
144
}
105
145
106
146
/// <summary>
@@ -250,6 +290,85 @@ static void Test_hostfxr_get_dotnet_environment_info(string[] args)
250
290
Console . WriteLine ( $ "{ api } framework paths:[{ string . Join ( ";" , frameworks . Select ( f => f . path ) . ToList ( ) ) } ]") ;
251
291
}
252
292
293
+ /// <summary>
294
+ /// Test that invokes hostfxr_resolve_frameworks_for_runtime_config.
295
+ /// </summary>
296
+ /// <param name="args[0]">Path to runtime config file</param>
297
+ /// <param name="args[1]">(Optional) Path to the directory with dotnet.exe</param>
298
+ static unsafe void Test_hostfxr_resolve_frameworks_for_runtime_config ( string [ ] args )
299
+ {
300
+ if ( args . Length < 1 )
301
+ throw new ArgumentException ( $ "Invalid arguments. Expected: { nameof ( hostfxr . hostfxr_resolve_frameworks_for_runtime_config ) } <runtimeConfigPath> [<dotnetRoot>]") ;
302
+
303
+ string runtimeConfigPath = args [ 0 ] ;
304
+ string dotnetRoot = null ;
305
+ if ( args . Length >= 2 )
306
+ dotnetRoot = args [ 1 ] ;
307
+
308
+ List < hostfxr . hostfxr_framework_result > resolved = new ( ) ;
309
+ List < hostfxr . hostfxr_framework_result > unresolved = new ( ) ;
310
+
311
+ IntPtr resultContext = new IntPtr ( 123 ) ;
312
+
313
+ hostfxr . hostfxr_resolve_frameworks_result_fn callback = ( IntPtr resultPtr , IntPtr contextPtr ) =>
314
+ {
315
+ hostfxr . hostfxr_resolve_frameworks_result result = Marshal . PtrToStructure < hostfxr . hostfxr_resolve_frameworks_result > ( resultPtr ) ;
316
+
317
+ if ( result . size != ( nuint ) sizeof ( hostfxr . hostfxr_resolve_frameworks_result ) )
318
+ throw new Exception ( $ "Unexpected { nameof ( hostfxr . hostfxr_resolve_frameworks_result ) } .size: { result . size } . Expected: { sizeof ( hostfxr . hostfxr_resolve_frameworks_result ) } .") ;
319
+
320
+ if ( contextPtr != resultContext )
321
+ throw new Exception ( $ "Unexpected result_context value: { contextPtr } . Expected: { resultContext } .") ;
322
+
323
+ for ( int i = 0 ; i < ( int ) result . resolved_count ; i ++ )
324
+ {
325
+ nint ptr = result . resolved_frameworks + i * Marshal . SizeOf < hostfxr . hostfxr_framework_result > ( ) ;
326
+ resolved . Add ( Marshal . PtrToStructure < hostfxr . hostfxr_framework_result > ( ptr ) ) ;
327
+ }
328
+
329
+ for ( int i = 0 ; i < ( int ) result . unresolved_count ; i ++ )
330
+ {
331
+ nint ptr = result . unresolved_frameworks + i * Marshal . SizeOf < hostfxr . hostfxr_framework_result > ( ) ;
332
+ unresolved . Add ( Marshal . PtrToStructure < hostfxr . hostfxr_framework_result > ( ptr ) ) ;
333
+ }
334
+ } ;
335
+
336
+ int rc ;
337
+ hostfxr . hostfxr_initialize_parameters parameters = new ( )
338
+ {
339
+ size = ( nuint ) sizeof ( hostfxr . hostfxr_initialize_parameters ) ,
340
+ host_path = IntPtr . Zero ,
341
+ dotnet_root = dotnetRoot != null ? Marshal . StringToCoTaskMemAuto ( dotnetRoot ) : IntPtr . Zero
342
+ } ;
343
+ try
344
+ {
345
+ rc = hostfxr . hostfxr_resolve_frameworks_for_runtime_config (
346
+ runtime_config_path : runtimeConfigPath ,
347
+ parameters : & parameters ,
348
+ callback : callback ,
349
+ result_context : resultContext ) ;
350
+ }
351
+ finally
352
+ {
353
+ Marshal . FreeCoTaskMem ( parameters . dotnet_root ) ;
354
+ }
355
+
356
+ string api = nameof ( hostfxr . hostfxr_resolve_frameworks_for_runtime_config ) ;
357
+ LogResult ( api , rc ) ;
358
+
359
+ Console . WriteLine ( $ "{ api } resolved_count: { resolved . Count } ") ;
360
+ foreach ( var framework in resolved )
361
+ {
362
+ Console . WriteLine ( $ "{ api } resolved_framework: name={ framework . name } , version={ framework . resolved_version } , path=[{ framework . resolved_path } ]") ;
363
+ }
364
+
365
+ Console . WriteLine ( $ "{ api } unresolved_count: { unresolved . Count } ") ;
366
+ foreach ( var framework in unresolved )
367
+ {
368
+ Console . WriteLine ( $ "{ api } unresolved_framework: name={ framework . name } , requested_version={ framework . requested_version } , path=[{ framework . resolved_path } ]") ;
369
+ }
370
+ }
371
+
253
372
private static void LogResult ( string apiName , int rc )
254
373
=> Console . WriteLine ( rc == 0 ? $ "{ apiName } :Success" : $ "{ apiName } :Fail[0x{ rc : x} ]") ;
255
374
@@ -269,6 +388,9 @@ public static bool RunTest(string apiToTest, string[] args)
269
388
case nameof ( hostfxr . hostfxr_get_dotnet_environment_info ) :
270
389
Test_hostfxr_get_dotnet_environment_info ( args ) ;
271
390
break ;
391
+ case nameof ( hostfxr . hostfxr_resolve_frameworks_for_runtime_config ) :
392
+ Test_hostfxr_resolve_frameworks_for_runtime_config ( args ) ;
393
+ break ;
272
394
default :
273
395
return false ;
274
396
}
0 commit comments