88
99namespace HostApiInvokerApp
1010{
11- public static class HostFXR
11+ public static unsafe class HostFXR
1212 {
1313 internal static class hostfxr
1414 {
@@ -59,6 +59,34 @@ internal struct hostfxr_dotnet_environment_info
5959 internal IntPtr frameworks ;
6060 }
6161
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+
6290 [ UnmanagedFunctionPointer ( CallingConvention . Cdecl , CharSet = CharSet . Auto ) ]
6391 internal delegate void hostfxr_resolve_sdk2_result_fn (
6492 hostfxr_resolve_sdk2_result_key_t key ,
@@ -101,6 +129,18 @@ internal static extern int hostfxr_get_dotnet_environment_info(
101129 IntPtr reserved ,
102130 hostfxr_get_dotnet_environment_info_result_fn result ,
103131 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 ) ;
104144 }
105145
106146 /// <summary>
@@ -250,6 +290,85 @@ static void Test_hostfxr_get_dotnet_environment_info(string[] args)
250290 Console . WriteLine ( $ "{ api } framework paths:[{ string . Join ( ";" , frameworks . Select ( f => f . path ) . ToList ( ) ) } ]") ;
251291 }
252292
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+
253372 private static void LogResult ( string apiName , int rc )
254373 => Console . WriteLine ( rc == 0 ? $ "{ apiName } :Success" : $ "{ apiName } :Fail[0x{ rc : x} ]") ;
255374
@@ -269,6 +388,9 @@ public static bool RunTest(string apiToTest, string[] args)
269388 case nameof ( hostfxr . hostfxr_get_dotnet_environment_info ) :
270389 Test_hostfxr_get_dotnet_environment_info ( args ) ;
271390 break ;
391+ case nameof ( hostfxr . hostfxr_resolve_frameworks_for_runtime_config ) :
392+ Test_hostfxr_resolve_frameworks_for_runtime_config ( args ) ;
393+ break ;
272394 default :
273395 return false ;
274396 }
0 commit comments