winget-cli

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

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