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/nuget/readme.md b/nuget/readme.md index 78d04bec7..cc027eca6 100644 --- a/nuget/readme.md +++ b/nuget/readme.md @@ -78,6 +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). 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 diff --git a/src/Authoring/WinRT.Host.Shim/Module.cs b/src/Authoring/WinRT.Host.Shim/Module.cs index bb90a0b3b..a896b1c37 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,52 @@ 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) + { + 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); + } + + 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) { *activationFactory = IntPtr.Zero; @@ -30,7 +78,19 @@ public static unsafe int GetActivationFactory(IntPtr hstrTargetAssembly, IntPtr try { +#if NET + Assembly assembly; + if (_IsLoadInDefaultContext) + { + assembly = LoadInDefaultContext(targetAssembly); + } + else + { + assembly = ActivationLoader.LoadAssembly(targetAssembly); + } +#else var assembly = ActivationLoader.LoadAssembly(targetAssembly); +#endif var type = assembly.GetType("WinRT.Module"); if (type == null) {