-
Notifications
You must be signed in to change notification settings - Fork 1.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Microsoft.WinGet.Client custom assembly load context #3150
Changes from all commits
31374a1
86e491a
efb8b21
37fac28
bf6094d
db6388d
05348f3
2d42dae
962753f
066139e
a1c0a0c
d8b30da
e651457
a36c558
02f4959
c1b3b29
1c7eb32
333b624
1d7eee3
8b7f46c
30d4673
fef41a2
737777f
22bda81
9580335
9b41a9f
50fefd8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
// ----------------------------------------------------------------------------- | ||
// <copyright file="ModuleInit.cs" company="Microsoft Corporation"> | ||
// Copyright (c) Microsoft Corporation. Licensed under the MIT License. | ||
// </copyright> | ||
// ----------------------------------------------------------------------------- | ||
#if !POWERSHELL_WINDOWS | ||
namespace Microsoft.WinGet.Client.Acl | ||
{ | ||
using System.Management.Automation; | ||
using System.Runtime.Loader; | ||
|
||
/// <summary> | ||
/// Initialization class for this module. | ||
/// </summary> | ||
public class ModuleInit : IModuleAssemblyInitializer, IModuleAssemblyCleanup | ||
{ | ||
/// <inheritdoc/> | ||
public void OnImport() | ||
{ | ||
AssemblyLoadContext.Default.Resolving += WinGetAssemblyLoadContext.ResolvingHandler; | ||
} | ||
|
||
/// <inheritdoc/> | ||
public void OnRemove(PSModuleInfo module) | ||
{ | ||
AssemblyLoadContext.Default.Resolving -= WinGetAssemblyLoadContext.ResolvingHandler; | ||
} | ||
} | ||
} | ||
#endif |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
// ----------------------------------------------------------------------------- | ||
// <copyright file="WinGetAssemblyLoadContext.cs" company="Microsoft Corporation"> | ||
// Copyright (c) Microsoft Corporation. Licensed under the MIT License. | ||
// </copyright> | ||
// ----------------------------------------------------------------------------- | ||
#if !POWERSHELL_WINDOWS | ||
namespace Microsoft.WinGet.Client.Acl | ||
{ | ||
using System; | ||
using System.IO; | ||
using System.Reflection; | ||
using System.Runtime.Loader; | ||
|
||
/// <summary> | ||
/// Custom assembly load context for this module. | ||
/// This helps us load our dependencies without carrying about apps importing this module. | ||
/// All dependencies except the Engine dll needs to be under a Dependencies directory. | ||
/// </summary> | ||
internal class WinGetAssemblyLoadContext : AssemblyLoadContext | ||
{ | ||
private static readonly string SharedDependencyPath = Path.Combine( | ||
Path.GetDirectoryName(typeof(WinGetAssemblyLoadContext).Assembly.Location), | ||
"SharedDependencies"); | ||
|
||
private static readonly string DirectDependencyPath = Path.Combine( | ||
Path.GetDirectoryName(typeof(WinGetAssemblyLoadContext).Assembly.Location), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It looks like you inverted the name suggestions that I used (completely, so functionally it should work). To me, the "shared" dependencies are the ones that might conflict (and so need to load from the ALC There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🫠 |
||
"DirectDependencies"); | ||
|
||
private static readonly WinGetAssemblyLoadContext WinGetAcl = new (); | ||
|
||
private WinGetAssemblyLoadContext() | ||
: base("WinGetAssemblyLoadContext", isCollectible: false) | ||
{ | ||
} | ||
|
||
/// <summary> | ||
/// Handler to resolve assemblies. | ||
/// </summary> | ||
/// <param name="context">Assembly load context.</param> | ||
/// <param name="assemblyName">Assembly name.</param> | ||
/// <returns>The assembly, null if not in our assembly location.</returns> | ||
internal static Assembly ResolvingHandler(AssemblyLoadContext context, AssemblyName assemblyName) | ||
{ | ||
string path = $"{Path.Combine(DirectDependencyPath, assemblyName.Name)}.dll"; | ||
if (File.Exists(path)) | ||
{ | ||
return WinGetAcl.LoadFromAssemblyName(assemblyName); | ||
} | ||
|
||
return null; | ||
} | ||
|
||
/// <inheritdoc/> | ||
protected override Assembly Load(AssemblyName assemblyName) | ||
{ | ||
string path = $"{Path.Combine(SharedDependencyPath, assemblyName.Name)}.dll"; | ||
if (File.Exists(path)) | ||
{ | ||
return this.LoadFromAssemblyPath(path); | ||
} | ||
|
||
path = $"{Path.Combine(DirectDependencyPath, assemblyName.Name)}.dll"; | ||
if (File.Exists(path)) | ||
{ | ||
return this.LoadFromAssemblyPath(path); | ||
} | ||
|
||
return null; | ||
} | ||
|
||
/// <inheritdoc/> | ||
protected override IntPtr LoadUnmanagedDll(string unmanagedDllName) | ||
{ | ||
string path = Path.Combine(SharedDependencyPath, unmanagedDllName); | ||
if (File.Exists(path)) | ||
{ | ||
return this.LoadUnmanagedDllFromPath(path); | ||
} | ||
|
||
return IntPtr.Zero; | ||
} | ||
} | ||
} | ||
#endif |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why aren't we able to create our own context and only use it when the assembly load is coming from this PS module?
My main worry is that if we change the default context, then we end up in a similar situation as without it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that my overall comment has more understanding than this one I made before reading the docs.