From 6b27c0b2343c72f674444793a7e82e9dfe69d74f Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sun, 13 Jul 2025 18:47:14 -0700 Subject: [PATCH 1/7] Add support for loading in default ALC --- src/Authoring/WinRT.Host.Shim/Module.cs | 39 +++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/src/Authoring/WinRT.Host.Shim/Module.cs b/src/Authoring/WinRT.Host.Shim/Module.cs index bb90a0b3b..027ceef54 100644 --- a/src/Authoring/WinRT.Host.Shim/Module.cs +++ b/src/Authoring/WinRT.Host.Shim/Module.cs @@ -3,10 +3,12 @@ using System; using System.Collections.Concurrent; +using System.Collections.Generic; using System.Reflection; #if NET using System.Runtime.Loader; +using System.Threading; [assembly: global::System.Runtime.Versioning.SupportedOSPlatform("Windows")] #endif @@ -21,6 +23,39 @@ public static class Shim public unsafe delegate int GetActivationFactoryDelegate(IntPtr hstrTargetAssembly, IntPtr hstrRuntimeClassId, IntPtr* activationFactory); +#if NET + private static HashSet _InitializedResolversInDefaultContext = null; + + public static Assembly LoadInDefaultContext(string targetAssembly) + { + if (_InitializedResolversInDefaultContext == null) + { + Interlocked.CompareExchange(ref _InitializedResolversInDefaultContext, new HashSet(StringComparer.OrdinalIgnoreCase), null); + } + + lock (_InitializedResolversInDefaultContext) + { + if (!_InitializedResolversInDefaultContext.Contains(targetAssembly)) + { + var resolver = new AssemblyDependencyResolver(targetAssembly); + AssemblyLoadContext.Default.Resolving += (AssemblyLoadContext assemblyLoadContext, AssemblyName assemblyName) => + { + string assemblyPath = resolver.ResolveAssemblyToPath(assemblyName); + if (assemblyPath != null) + { + return assemblyLoadContext.LoadFromAssemblyPath(assemblyPath); + } + return null; + }; + + _InitializedResolversInDefaultContext.Add(targetAssembly); + } + } + + return AssemblyLoadContext.Default.LoadFromAssemblyPath(targetAssembly); + } +#endif + public static unsafe int GetActivationFactory(IntPtr hstrTargetAssembly, IntPtr hstrRuntimeClassId, IntPtr* activationFactory) { *activationFactory = IntPtr.Zero; @@ -30,7 +65,11 @@ public static unsafe int GetActivationFactory(IntPtr hstrTargetAssembly, IntPtr try { +#if NET + var assembly = LoadInDefaultContext(targetAssembly); +#else var assembly = ActivationLoader.LoadAssembly(targetAssembly); +#endif var type = assembly.GetType("WinRT.Module"); if (type == null) { From 60eb969c50ac330053be8aed26d29100e104abd2 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sun, 13 Jul 2025 20:22:03 -0700 Subject: [PATCH 2/7] Put behind feature switch --- nuget/Microsoft.Windows.CsWinRT.targets | 6 ++++++ src/Authoring/WinRT.Host.Shim/Module.cs | 23 ++++++++++++++++++++++- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/nuget/Microsoft.Windows.CsWinRT.targets b/nuget/Microsoft.Windows.CsWinRT.targets index 0966cfc4c..dbb87848f 100644 --- a/nuget/Microsoft.Windows.CsWinRT.targets +++ b/nuget/Microsoft.Windows.CsWinRT.targets @@ -567,6 +567,7 @@ $(CsWinRTInternalProjection) true true false + false + diff --git a/src/Authoring/WinRT.Host.Shim/Module.cs b/src/Authoring/WinRT.Host.Shim/Module.cs index 027ceef54..a896b1c37 100644 --- a/src/Authoring/WinRT.Host.Shim/Module.cs +++ b/src/Authoring/WinRT.Host.Shim/Module.cs @@ -24,6 +24,9 @@ public static class Shim public unsafe delegate int GetActivationFactoryDelegate(IntPtr hstrTargetAssembly, IntPtr hstrRuntimeClassId, IntPtr* activationFactory); #if NET + private const string UseLoadComponentsInDefaultALCPropertyName = "CSWINRT_LOAD_COMPONENTS_IN_DEFAULT_ALC"; + private readonly static bool _IsLoadInDefaultContext = IsLoadInDefaultContext(); + private static HashSet _InitializedResolversInDefaultContext = null; public static Assembly LoadInDefaultContext(string targetAssembly) @@ -54,6 +57,16 @@ public static Assembly LoadInDefaultContext(string targetAssembly) return AssemblyLoadContext.Default.LoadFromAssemblyPath(targetAssembly); } + + public static bool IsLoadInDefaultContext() + { + if (AppContext.TryGetSwitch(UseLoadComponentsInDefaultALCPropertyName, out bool isEnabled)) + { + return isEnabled; + } + + return false; + } #endif public static unsafe int GetActivationFactory(IntPtr hstrTargetAssembly, IntPtr hstrRuntimeClassId, IntPtr* activationFactory) @@ -66,7 +79,15 @@ public static unsafe int GetActivationFactory(IntPtr hstrTargetAssembly, IntPtr try { #if NET - var assembly = LoadInDefaultContext(targetAssembly); + Assembly assembly; + if (_IsLoadInDefaultContext) + { + assembly = LoadInDefaultContext(targetAssembly); + } + else + { + assembly = ActivationLoader.LoadAssembly(targetAssembly); + } #else var assembly = ActivationLoader.LoadAssembly(targetAssembly); #endif From 21de993f3df7e5dac7273fec2a049828a755f87a Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sun, 13 Jul 2025 20:31:56 -0700 Subject: [PATCH 3/7] Update readme --- nuget/readme.md | 1 + 1 file changed, 1 insertion(+) diff --git a/nuget/readme.md b/nuget/readme.md index 78d04bec7..72e7ff34b 100644 --- a/nuget/readme.md +++ b/nuget/readme.md @@ -79,6 +79,7 @@ C#/WinRT supports several feature switches to opt-out of some features available | CsWinRTEnableIReferenceSupport | \*true \| false | Enables support and marshalling of `IReference`, `IReferenceArray` and `IPropertyValue` objects. Setting this to **false** allows trimming all supporting code for all three interfaces, and will make all of them not available on marshalled CCW types. | | CsWinRTEnableIDynamicInterfaceCastableSupport | \*true \| false | Enables support for the [`IDynamicInterfaceCastable`](https://devblogs.microsoft.com/dotnet/improvements-in-native-code-interop-in-net-5-0/#idynamicinterfacecastable) infrastructure for RCW types. Setting this to **false** allows trimming of all related code, and will disallow casting RCW types to interface types they don't directly implement in metadata. | \*Default value +| CsWinRTLoadComponentsInDefaultALC | true \| \*false | Setting this to **true** configures `WinRT.Host.dll` to load CsWinRT components in the default Assembly Load Context (ALC). By default, when set to **false**, they load in their own ALC. | ### Windows Metadata From 913993ff91b9eecadda88e323d1ed18bc8e4dd93 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sun, 13 Jul 2025 20:33:02 -0700 Subject: [PATCH 4/7] Reorder --- nuget/readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nuget/readme.md b/nuget/readme.md index 72e7ff34b..299440bd4 100644 --- a/nuget/readme.md +++ b/nuget/readme.md @@ -78,8 +78,8 @@ C#/WinRT supports several feature switches to opt-out of some features available | CsWinRTEnableICustomPropertyProviderSupport | \*true \| false | Enables marshalling of `ICustomPropertyProvider` objects. Setting this to **false** allows trimming all supporting code for this interface, and will make it not available on marshalled CCW types. | | CsWinRTEnableIReferenceSupport | \*true \| false | Enables support and marshalling of `IReference`, `IReferenceArray` and `IPropertyValue` objects. Setting this to **false** allows trimming all supporting code for all three interfaces, and will make all of them not available on marshalled CCW types. | | CsWinRTEnableIDynamicInterfaceCastableSupport | \*true \| false | Enables support for the [`IDynamicInterfaceCastable`](https://devblogs.microsoft.com/dotnet/improvements-in-native-code-interop-in-net-5-0/#idynamicinterfacecastable) infrastructure for RCW types. Setting this to **false** allows trimming of all related code, and will disallow casting RCW types to interface types they don't directly implement in metadata. | -\*Default value | CsWinRTLoadComponentsInDefaultALC | true \| \*false | Setting this to **true** configures `WinRT.Host.dll` to load CsWinRT components in the default Assembly Load Context (ALC). By default, when set to **false**, they load in their own ALC. | +\*Default value ### Windows Metadata From 9287600f3a042e2346f8288e47f16f10de38c33b Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sun, 13 Jul 2025 20:40:32 -0700 Subject: [PATCH 5/7] Add link --- nuget/readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nuget/readme.md b/nuget/readme.md index 299440bd4..de4372a0a 100644 --- a/nuget/readme.md +++ b/nuget/readme.md @@ -78,7 +78,7 @@ C#/WinRT supports several feature switches to opt-out of some features available | CsWinRTEnableICustomPropertyProviderSupport | \*true \| false | Enables marshalling of `ICustomPropertyProvider` objects. Setting this to **false** allows trimming all supporting code for this interface, and will make it not available on marshalled CCW types. | | CsWinRTEnableIReferenceSupport | \*true \| false | Enables support and marshalling of `IReference`, `IReferenceArray` and `IPropertyValue` objects. Setting this to **false** allows trimming all supporting code for all three interfaces, and will make all of them not available on marshalled CCW types. | | CsWinRTEnableIDynamicInterfaceCastableSupport | \*true \| false | Enables support for the [`IDynamicInterfaceCastable`](https://devblogs.microsoft.com/dotnet/improvements-in-native-code-interop-in-net-5-0/#idynamicinterfacecastable) infrastructure for RCW types. Setting this to **false** allows trimming of all related code, and will disallow casting RCW types to interface types they don't directly implement in metadata. | -| CsWinRTLoadComponentsInDefaultALC | true \| \*false | Setting this to **true** configures `WinRT.Host.dll` to load CsWinRT components in the default Assembly Load Context (ALC). By default, when set to **false**, they load in their own ALC. | +| CsWinRTLoadComponentsInDefaultALC | true \| \*false | Setting this to **true** configures `WinRT.Host.dll` to load CsWinRT components in the default [`Assembly Load Context (ALC)`](https://learn.microsoft.com/en-us/dotnet/core/dependency-loading/understanding-assemblyloadcontext). By default, when set to **false**, they load in their own ALC. | \*Default value ### Windows Metadata From aa3a749daeee8cf592855931729a81610fe3f292 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sun, 13 Jul 2025 20:41:47 -0700 Subject: [PATCH 6/7] Fix url --- nuget/readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nuget/readme.md b/nuget/readme.md index de4372a0a..97b84109f 100644 --- a/nuget/readme.md +++ b/nuget/readme.md @@ -78,7 +78,7 @@ C#/WinRT supports several feature switches to opt-out of some features available | CsWinRTEnableICustomPropertyProviderSupport | \*true \| false | Enables marshalling of `ICustomPropertyProvider` objects. Setting this to **false** allows trimming all supporting code for this interface, and will make it not available on marshalled CCW types. | | CsWinRTEnableIReferenceSupport | \*true \| false | Enables support and marshalling of `IReference`, `IReferenceArray` and `IPropertyValue` objects. Setting this to **false** allows trimming all supporting code for all three interfaces, and will make all of them not available on marshalled CCW types. | | CsWinRTEnableIDynamicInterfaceCastableSupport | \*true \| false | Enables support for the [`IDynamicInterfaceCastable`](https://devblogs.microsoft.com/dotnet/improvements-in-native-code-interop-in-net-5-0/#idynamicinterfacecastable) infrastructure for RCW types. Setting this to **false** allows trimming of all related code, and will disallow casting RCW types to interface types they don't directly implement in metadata. | -| CsWinRTLoadComponentsInDefaultALC | true \| \*false | Setting this to **true** configures `WinRT.Host.dll` to load CsWinRT components in the default [`Assembly Load Context (ALC)`](https://learn.microsoft.com/en-us/dotnet/core/dependency-loading/understanding-assemblyloadcontext). By default, when set to **false**, they load in their own ALC. | +| CsWinRTLoadComponentsInDefaultALC | true \| \*false | Setting this to **true** configures `WinRT.Host.dll` to load CsWinRT components in the default [`Assembly Load Context (ALC)`](https://learn.microsoft.com/dotnet/core/dependency-loading/understanding-assemblyloadcontext). By default, when set to **false**, they load in their own ALC. | \*Default value ### Windows Metadata From 4bc1b137ec76f31449b8cd122c82429ba92b943a Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sun, 13 Jul 2025 20:53:22 -0700 Subject: [PATCH 7/7] Add warning --- nuget/readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nuget/readme.md b/nuget/readme.md index 97b84109f..cc027eca6 100644 --- a/nuget/readme.md +++ b/nuget/readme.md @@ -78,7 +78,7 @@ C#/WinRT supports several feature switches to opt-out of some features available | CsWinRTEnableICustomPropertyProviderSupport | \*true \| false | Enables marshalling of `ICustomPropertyProvider` objects. Setting this to **false** allows trimming all supporting code for this interface, and will make it not available on marshalled CCW types. | | CsWinRTEnableIReferenceSupport | \*true \| false | Enables support and marshalling of `IReference`, `IReferenceArray` and `IPropertyValue` objects. Setting this to **false** allows trimming all supporting code for all three interfaces, and will make all of them not available on marshalled CCW types. | | CsWinRTEnableIDynamicInterfaceCastableSupport | \*true \| false | Enables support for the [`IDynamicInterfaceCastable`](https://devblogs.microsoft.com/dotnet/improvements-in-native-code-interop-in-net-5-0/#idynamicinterfacecastable) infrastructure for RCW types. Setting this to **false** allows trimming of all related code, and will disallow casting RCW types to interface types they don't directly implement in metadata. | -| CsWinRTLoadComponentsInDefaultALC | true \| \*false | Setting this to **true** configures `WinRT.Host.dll` to load CsWinRT components in the default [`Assembly Load Context (ALC)`](https://learn.microsoft.com/dotnet/core/dependency-loading/understanding-assemblyloadcontext). By default, when set to **false**, they load in their own ALC. | +| CsWinRTLoadComponentsInDefaultALC | true \| \*false | Setting this to **true** configures `WinRT.Host.dll` to load CsWinRT components in the default [`Assembly Load Context (ALC)`](https://learn.microsoft.com/dotnet/core/dependency-loading/understanding-assemblyloadcontext). Note you should ensure components and dependencies loaded are compatible and will not conflict in any way to avoid potential issues. By default, when set to **false**, they load in their own ALC. | \*Default value ### Windows Metadata