WinGetAssemblyLoadContext.cs (5362B)
1 // ----------------------------------------------------------------------------- 2 // <copyright file="WinGetAssemblyLoadContext.cs" company="Microsoft Corporation"> 3 // Copyright (c) Microsoft Corporation. Licensed under the MIT License. 4 // </copyright> 5 // ----------------------------------------------------------------------------- 6 #if !POWERSHELL_WINDOWS 7 namespace Microsoft.WinGet.Resolver 8 { 9 using System; 10 using System.Collections.Generic; 11 using System.IO; 12 using System.Linq; 13 using System.Reflection; 14 using System.Runtime.InteropServices; 15 using System.Runtime.Loader; 16 17 /// <summary> 18 /// Custom assembly load context for this module. 19 /// This helps us load our dependencies without carrying about apps importing this module. 20 /// All dependencies except the Engine dll needs to be under a Dependencies directory. 21 /// </summary> 22 internal class WinGetAssemblyLoadContext : AssemblyLoadContext 23 { 24 // The assemblies must be loaded in the default context. 25 // Loading WinRT.Runtime.dll in an ALC when is already loaded in the default context 26 // will result on 'Attempt to update previously set global instance.' 27 private static readonly IEnumerable<string> DefaultContextAssemblies = new string[] 28 { 29 @"WinRT.Runtime.dll", 30 }; 31 32 private static readonly string SharedDependencyPath; 33 private static readonly string SharedArchDependencyPath; 34 private static readonly string DirectDependencyPath; 35 36 private static readonly WinGetAssemblyLoadContext WinGetAcl = new (); 37 38 static WinGetAssemblyLoadContext() 39 { 40 var self = typeof(WinGetAssemblyLoadContext).Assembly; 41 SharedDependencyPath = Path.Combine( 42 Path.GetDirectoryName(self.Location), 43 "SharedDependencies"); 44 SharedArchDependencyPath = Path.Combine( 45 SharedDependencyPath, 46 RuntimeInformation.ProcessArchitecture.ToString().ToLower()); 47 DirectDependencyPath = Path.Combine( 48 Path.GetDirectoryName(self.Location), 49 "DirectDependencies"); 50 } 51 52 private WinGetAssemblyLoadContext() 53 : base("WinGetAssemblyLoadContext", isCollectible: false) 54 { 55 } 56 57 /// <summary> 58 /// Handler to resolve assemblies. 59 /// </summary> 60 /// <param name="context">Assembly load context.</param> 61 /// <param name="assemblyName">Assembly name.</param> 62 /// <returns>The assembly, null if not in our assembly location.</returns> 63 internal static Assembly ResolvingHandler(AssemblyLoadContext context, AssemblyName assemblyName) 64 { 65 string name = $"{assemblyName.Name}.dll"; 66 if (DefaultContextAssemblies.Any(a => a.Equals(name, StringComparison.OrdinalIgnoreCase))) 67 { 68 string sharedPath = Path.Combine(SharedDependencyPath, name); 69 if (File.Exists(sharedPath)) 70 { 71 return AssemblyLoadContext.Default.LoadFromAssemblyPath(sharedPath); 72 } 73 } 74 75 string path = Path.Combine(DirectDependencyPath, name); 76 if (File.Exists(path)) 77 { 78 return WinGetAcl.LoadFromAssemblyName(assemblyName); 79 } 80 81 return null; 82 } 83 84 /// <summary> 85 /// Handler to resolve unmanaged assemblies. 86 /// </summary> 87 /// <param name="assembly">Assembly initiating the unmanaged load.</param> 88 /// <param name="unmanagedDllName">Unmanaged dll name.</param> 89 /// <returns>The assembly ptr, zero if not in our assembly location.</returns> 90 internal static IntPtr ResolvingUnmanagedDllHandler(Assembly assembly, string unmanagedDllName) 91 { 92 return WinGetAcl.LoadUnmanagedDll(unmanagedDllName); 93 } 94 95 /// <inheritdoc/> 96 protected override Assembly Load(AssemblyName assemblyName) 97 { 98 string name = $"{assemblyName.Name}.dll"; 99 if (DefaultContextAssemblies.Any(a => a.Equals(name, StringComparison.OrdinalIgnoreCase))) 100 { 101 return null; 102 } 103 104 string path = Path.Combine(SharedDependencyPath, name); 105 if (File.Exists(path)) 106 { 107 return this.LoadFromAssemblyPath(path); 108 } 109 110 path = Path.Combine(SharedArchDependencyPath, name); 111 if (File.Exists(path)) 112 { 113 return this.LoadFromAssemblyPath(path); 114 } 115 116 path = Path.Combine(DirectDependencyPath, name); 117 if (File.Exists(path)) 118 { 119 return this.LoadFromAssemblyPath(path); 120 } 121 122 return null; 123 } 124 125 /// <inheritdoc/> 126 protected override IntPtr LoadUnmanagedDll(string unmanagedDllName) 127 { 128 string path = Path.Combine(SharedArchDependencyPath, unmanagedDllName); 129 if (File.Exists(path)) 130 { 131 return this.LoadUnmanagedDllFromPath(path); 132 } 133 134 return IntPtr.Zero; 135 } 136 } 137 } 138 #endif