[PTRun] PowerToys Run - plugin dependency loading (#30513)

* Updated the Wox.Plugin to correctly load and resolve plugin dependecies

* Included new plugin.props in all plugins to enable dynamic dependecy loading

* Updated dev docs to include new plugin.props in plugins

* Fixed double dependecy loading bug

* - Updated to only use dynamic loading when explicitly set by the plugin.
- Removed no longer required props from default plugins which do not need dynamic loading.
- Updated dev-docs to align with latest changes

* Removed line spacing changes in plugins csproj

* fixed spelling

* csproj cleanup

* removed unnecessary null checking

---------

Co-authored-by: Corey Hayward <coreyh@tigereyeconsulting.com>
This commit is contained in:
coreyH 2023-12-26 09:19:15 +00:00 committed by GitHub
parent 3e45392274
commit c098cfb193
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 71 additions and 2 deletions

View File

@ -3,6 +3,7 @@
- [ ] Microsoft plugin project name pattern: `Microsoft.PowerToys.Run.Plugin.{PluginName}`
- [ ] Community plugin project name pattern: `Community.PowerToys.Run.Plugin.{PluginName}`
- [ ] The project file should import `Version.props` and specify `<Version>$(Version).0</Version>`
- [ ] If the plugin uses any 3rd party dependencies the project file should import `DynamicPlugin.props`
- [ ] Make sure `*.csproj` specify only x64 platform target
- [ ] The plugin has to contain a `plugin.json` file of the following format in its root folder
```
@ -17,7 +18,8 @@
"Website": "https://aka.ms/powertoys",
"ExecuteFileName": string, // Should be {Type}.PowerToys.Run.Plugin.{PluginName}.dll
"IcoPathDark": string, // Path to dark theme icon. The path is relative to the root plugin folder
"IcoPathLight": string // Path to light theme icon. The path is relative to the root plugin folder
"IcoPathLight": string // Path to light theme icon. The path is relative to the root plugin folder
"DynamicLoading": bool // Sets whether the plugin should dynamically load any dependencies isolated from the core application.
}
```
- [ ] Make sure your `Main` class contains a public, static string property for the `PluginID`. The plugin id has to be the same as the one in the `plugin.json`file.

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<EnableDynamicLoading>true</EnableDynamicLoading>
</PropertyGroup>
<ItemDefinitionGroup>
<ProjectReference>
<Private Condition="'$(OutputType)' == 'library'">false</Private>
</ProjectReference>
</ItemDefinitionGroup>
</Project>

View File

@ -0,0 +1,44 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Linq;
using System.Reflection;
using System.Runtime.Loader;
namespace Wox.Plugin
{
internal class PluginLoadContext : AssemblyLoadContext
{
private AssemblyDependencyResolver _resolver;
public PluginLoadContext(string pluginPath)
{
_resolver = new AssemblyDependencyResolver(pluginPath);
}
protected override Assembly Load(AssemblyName assemblyName)
{
string assemblyPath = _resolver.ResolveAssemblyToPath(assemblyName);
if (assemblyPath != null)
{
var existingAssembly = Default.Assemblies.FirstOrDefault(x => x.FullName == assemblyName.FullName);
return existingAssembly ?? LoadFromAssemblyPath(assemblyPath);
}
return null;
}
protected override IntPtr LoadUnmanagedDll(string unmanagedDllName)
{
string libraryPath = _resolver.ResolveUnmanagedDllToPath(unmanagedDllName);
if (libraryPath != null)
{
return LoadUnmanagedDllFromPath(libraryPath);
}
return IntPtr.Zero;
}
}
}

View File

@ -65,6 +65,8 @@ namespace Wox.Plugin
public string IcoPathLight { get; set; }
public bool DynamicLoading { get; set; }
public override string ToString()
{
return Name;

View File

@ -4,6 +4,7 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Loader;
@ -153,7 +154,15 @@ namespace Wox.Plugin
try
{
_assembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(Metadata.ExecuteFilePath);
if (Metadata.DynamicLoading)
{
var loadContext = new PluginLoadContext(Metadata.ExecuteFilePath);
_assembly = loadContext.LoadFromAssemblyName(new AssemblyName(Path.GetFileNameWithoutExtension(Metadata.ExecuteFilePath)));
}
else
{
_assembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(Metadata.ExecuteFilePath);
}
}
catch (Exception e)
{