Skip to content

Commit

Permalink
feat: 新插件加载逻辑, 插件模板
Browse files Browse the repository at this point in the history
  • Loading branch information
Saplonily committed Jan 23, 2025
1 parent a13bcdb commit 100a1a5
Show file tree
Hide file tree
Showing 49 changed files with 418 additions and 448 deletions.
Original file line number Diff line number Diff line change
@@ -1,37 +1,30 @@
<Project Sdk="Microsoft.NET.Sdk">

<Import Project="..\..\Plugins\Plugin.props" />

<PropertyGroup>
<OutputType>Library</OutputType>
<TargetFramework>net8.0-windows</TargetFramework>

<!-- 自动复制NuGet包到输出目录 -->
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
<GenerateDependencyFile>false</GenerateDependencyFile>
</PropertyGroup>

<ItemGroup>
<Compile Include="SHLoadIndirectStringList.fs" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\CurvaLauncher.Plugins\CurvaLauncher.Plugins.csproj" />
<Content Include="Manifest.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>

<ItemGroup>
<PackageReference Update="FSharp.Core" Version="8.0.101" />
</ItemGroup>


<Target Name="CopyFSharpCore" AfterTargets="Build">
<Copy SourceFiles="$(OutDir)\FSharp.Core.dll" DestinationFiles="..\..\CurvaLauncher\bin\$(Configuration)\$(TargetFramework)\Libraries\FSharp.Core.dll"></Copy>
</Target>

<Target Name="CopyOutputDebug" AfterTargets="Build" Condition="'$(Configuration)'=='Debug'">
<Copy SourceFiles="$(OutDir)\$(MSBuildProjectName).dll" DestinationFiles="..\..\CurvaLauncher\bin\$(Configuration)\$(TargetFramework)\Plugins\$(MSBuildProjectName).dll"></Copy>
<Copy SourceFiles="$(OutDir)\$(MSBuildProjectName).pdb" DestinationFiles="..\..\CurvaLauncher\bin\$(Configuration)\$(TargetFramework)\Plugins\$(MSBuildProjectName).pdb"></Copy>
</Target>

<Target Name="CopyOutputRelease" AfterTargets="Build" Condition="'$(Configuration)'=='Release'">
<Copy SourceFiles="$(OutDir)\$(MSBuildProjectName).dll" DestinationFiles="..\..\CurvaLauncher\bin\$(Configuration)\$(TargetFramework)\AdditionalPlugins\$(MSBuildProjectName).dll"></Copy>
</Target>
<Import Project="..\..\Plugins\PackAfterBuild.targets" />

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"ID": "SHLoadIndirectStringList",
"Assembly": "CurvaLauncher.Plugins.SHLoadIndirectStringList.dll"
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,20 +31,6 @@ type public StringQueryResult(title, desc, weight) =
type public SHLoadIndirectStringPlugin(context: CurvaLauncherContext) =
inherit SyncPlugin(context)

static do
AppDomain.CurrentDomain.add_AssemblyResolve(fun _ args ->
let asmName = new AssemblyName(args.Name)
let dllName = "FSharp.Core.dll"
if asmName.Name = "FSharp.Core" then
[|
(Path.Combine(AppContext.BaseDirectory, dllName))
(Path.Combine(AppContext.BaseDirectory, "Libraries", dllName));
(Path.Combine(Directory.GetCurrentDirectory(), dllName))
|].Where(File.Exists).First() |> Assembly.LoadFrom
else
null
)

[<DllImport("shlwapi.dll", EntryPoint = "SHLoadIndirectString", CharSet = CharSet.Unicode, ExactSpelling = true)>]
static extern uint SHLoadIndirectString(string pszSource, char& pszOutBuf, int cchOutBuf, nativeint ppvReserved)

Expand Down
29 changes: 29 additions & 0 deletions src/CurvaLauncher.Plugins/PluginAssemblyLoadContext.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.Loader;

namespace CurvaLauncher.Plugins;

public sealed class PluginAssemblyLoadContext : AssemblyLoadContext
{
private readonly AssemblyDependencyResolver resolver;

public PluginAssemblyLoadContext(string pluginID, string dllPath)
: base($"ZipPlugin ALC - {pluginID}")
{
resolver = new(dllPath);
}

protected override Assembly? Load(AssemblyName assemblyName)
{
string? resolvedPath = resolver.ResolveAssemblyToPath(assemblyName);
return resolvedPath is not null ? LoadFromAssemblyPath(resolvedPath) : null;
}

protected override nint LoadUnmanagedDll(string unmanagedDllName)
{
string? resolvedPath = resolver.ResolveUnmanagedDllToPath(unmanagedDllName);
return resolvedPath is not null ? LoadUnmanagedDllFromPath(resolvedPath) : IntPtr.Zero;
}
}
3 changes: 3 additions & 0 deletions src/CurvaLauncher.Plugins/PluginManifest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
namespace CurvaLauncher.Plugins;

public sealed record PluginManifest(string ID, string Assembly);
12 changes: 12 additions & 0 deletions src/CurvaLauncher.Plugins/PluginTypeAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace CurvaLauncher.Plugins;

[AttributeUsage(AttributeTargets.Assembly)]
public sealed class PluginTypeAttribute : Attribute
{
public Type PluginType { get; private set; }

public PluginTypeAttribute(Type pluginType)
{
PluginType = pluginType;
}
}
16 changes: 3 additions & 13 deletions src/CurvaLauncher.sln
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CurvaLauncher.Plugins.Every
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{F36EDE5B-9C67-44F4-87A9-792390FECF85}"
ProjectSection(SolutionItems) = preProject
Plugins\CopyAfterBuild.targets = Plugins\CopyAfterBuild.targets
CurvaLauncher.props = CurvaLauncher.props
Plugins\PackAfterBuild.targets = Plugins\PackAfterBuild.targets
Plugins\Plugin.props = Plugins\Plugin.props
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Templates", "Templates", "{45D0660D-436E-4419-AEB9-B6ED5BC3E0ED}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CurvaLauncher.PluginTemplate", "Templates\CurvaLauncher.PluginTemplate\CurvaLauncher.PluginTemplate.csproj", "{702E5FF3-99D0-4FD3-86E2-04C0A2E82560}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -174,14 +173,6 @@ Global
{C7AC6C75-89C6-42E5-8D2A-D06994949F05}.Release|Any CPU.Build.0 = Release|Any CPU
{C7AC6C75-89C6-42E5-8D2A-D06994949F05}.Release|x64.ActiveCfg = Release|x64
{C7AC6C75-89C6-42E5-8D2A-D06994949F05}.Release|x64.Build.0 = Release|x64
{702E5FF3-99D0-4FD3-86E2-04C0A2E82560}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{702E5FF3-99D0-4FD3-86E2-04C0A2E82560}.Debug|Any CPU.Build.0 = Debug|Any CPU
{702E5FF3-99D0-4FD3-86E2-04C0A2E82560}.Debug|x64.ActiveCfg = Debug|Any CPU
{702E5FF3-99D0-4FD3-86E2-04C0A2E82560}.Debug|x64.Build.0 = Debug|Any CPU
{702E5FF3-99D0-4FD3-86E2-04C0A2E82560}.Release|Any CPU.ActiveCfg = Release|Any CPU
{702E5FF3-99D0-4FD3-86E2-04C0A2E82560}.Release|Any CPU.Build.0 = Release|Any CPU
{702E5FF3-99D0-4FD3-86E2-04C0A2E82560}.Release|x64.ActiveCfg = Release|Any CPU
{702E5FF3-99D0-4FD3-86E2-04C0A2E82560}.Release|x64.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -198,7 +189,6 @@ Global
{F3F6F783-4636-457F-80E1-CC489F524B43} = {BAACD50D-2F94-4A65-8B13-49031D617CAC}
{8CFC1C29-51AA-45ED-A91F-01F513182002} = {4A86F98E-B276-4F75-9847-8D0E4280D887}
{C7AC6C75-89C6-42E5-8D2A-D06994949F05} = {BAACD50D-2F94-4A65-8B13-49031D617CAC}
{702E5FF3-99D0-4FD3-86E2-04C0A2E82560} = {45D0660D-436E-4419-AEB9-B6ED5BC3E0ED}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {3FC4E11A-3D67-43DE-84D8-DCA1841F0D71}
Expand Down
8 changes: 1 addition & 7 deletions src/CurvaLauncher/App.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ private static IServiceProvider BuildServiceProvider()
services.AddSingleton<HotkeyService>();
services.AddSingleton<PluginService>();
services.AddSingleton<ConfigService>();
services.AddSingleton<LibraryService>();
services.AddSingleton<ThemeService>();
services.AddSingleton<I18nService>();
services.AddTransient<PageService>();
Expand Down Expand Up @@ -81,8 +80,6 @@ protected override void OnStartup(StartupEventArgs e)
.GetRequiredService<HotkeyService>();
var themeService = ServiceProvider
.GetRequiredService<ThemeService>();
var libraryService = ServiceProvider
.GetRequiredService<LibraryService>();
var globalizationService = ServiceProvider
.GetRequiredService<I18nService>();

Expand All @@ -91,9 +88,6 @@ protected override void OnStartup(StartupEventArgs e)
//new WindowInteropHelper(mainWindow)
// .EnsureHandle();

// 加载库
libraryService.Setup();

// 加载插件
pluginService.LoadAllPlugins();

Expand Down Expand Up @@ -215,7 +209,7 @@ public static void ShowLauncherWithQuery(string queryText)

public static void CloseLauncher()
{
var mainWindow =
var mainWindow =
ServiceProvider.GetRequiredService<MainWindow>();

mainWindow.ViewModel.QueryText = string.Empty;
Expand Down
58 changes: 0 additions & 58 deletions src/CurvaLauncher/Services/LibraryService.cs

This file was deleted.

46 changes: 15 additions & 31 deletions src/CurvaLauncher/Services/PluginService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,14 @@
using System.Linq;
using System.Reflection;
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Text.Json.Serialization.Metadata;
using System.Threading.Tasks;
using CommunityToolkit.Mvvm.Input;
using CurvaLauncher.Models;
using CurvaLauncher.Plugins;
using CurvaLauncher.PluginInteraction;
using System.Diagnostics;
using System.IO.Compression;
using System.Runtime.Loader;
using IOPath = System.IO.Path;

namespace CurvaLauncher.Services;

Expand Down Expand Up @@ -141,34 +139,20 @@ private bool CoreLoadZipPlugin(AppConfig config, string zipFilePath, [NotNullWhe
try
{
using var zipFile = File.OpenRead(zipFilePath);
using var zipArchive = new ZipArchive(zipFile, ZipArchiveMode.Read);
var assemblyLoadContext = new AssemblyLoadContext(null, false);

foreach (var entry in zipArchive.Entries)
{
if (!entry.FullName.EndsWith(".dll", StringComparison.OrdinalIgnoreCase))
{
continue;
}

using var entryStream = entry.Open();

try
{
var assembly = assemblyLoadContext.LoadFromStream(entryStream);

if (pluginInstance is null)
{
CoreLoadPluginFromAssembly(config, assembly, out pluginInstance);
}
}
catch (Exception ex)
{
Debug.WriteLine($"DLL load failed, {ex}");
}
}

return pluginInstance is not null;
string extractDir = IOPath.Combine(".cache", IOPath.GetFileNameWithoutExtension(zipFilePath));
if (Directory.Exists(extractDir))
Directory.Delete(extractDir, true);
ZipFile.ExtractToDirectory(zipFile, extractDir);

var manifestJson = File.ReadAllText(IOPath.Combine(extractDir, "Manifest.json"));
var manifest = JsonSerializer.Deserialize<PluginManifest>(manifestJson);
if (manifest is null)
return false;

var assemblyPath = IOPath.GetFullPath(IOPath.Combine(extractDir, manifest.Assembly));
var alc = new PluginAssemblyLoadContext(manifest.ID, assemblyPath);
Assembly assembly = alc.LoadFromAssemblyPath(assemblyPath);
return CoreLoadPluginFromAssembly(config, assembly, out pluginInstance);
}
catch (Exception ex)
{
Expand Down
13 changes: 13 additions & 0 deletions src/Plugins/CopyAfterBuild.targets
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<Project>

<Target Name="CopyOutput" AfterTargets="Build">
<ItemGroup>
<_CompileOutput Include="$(OutputPath)\**"/>
</ItemGroup>

<Copy SourceFiles="@(_CompileOutput)"
DestinationFolder="..\..\CurvaLauncher\bin\$(Configuration)\$(TargetFramework)\Plugins\%(RecursiveDir)"
SkipUnchangedFiles="true"/>
</Target>

</Project>
4 changes: 4 additions & 0 deletions src/Plugins/CurvaLauncher.Plugins.Calculator/AssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
using CurvaLauncher.Plugins;
using CurvaLauncher.Plugins.Calculator;

[assembly: PluginType(typeof(CalculatorPlugin))]
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<Import Project="..\Plugin.props" />

<PropertyGroup>
<TargetFramework>net8.0-windows</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
Expand All @@ -8,10 +10,6 @@
<EnableWindowsTargeting>true</EnableWindowsTargeting>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\..\CurvaLauncher.Plugins\CurvaLauncher.Plugins.csproj" />
</ItemGroup>

<ItemGroup>
<Compile Update="Properties\Resources.Designer.cs">
<DesignTime>True</DesignTime>
Expand All @@ -27,12 +25,6 @@
</EmbeddedResource>
</ItemGroup>

<Target Name="CopyOutput" AfterTargets="Build">
<Copy SourceFiles="$(OutDir)\$(MSBuildProjectName).dll" DestinationFiles="..\..\CurvaLauncher\bin\$(Configuration)\$(TargetFramework)\Plugins\$(MSBuildProjectName).dll"></Copy>
</Target>
<Import Project="..\CopyAfterBuild.targets" />

<Target Name="CopyOutputPdb" AfterTargets="Build" Condition="'$(Configuration)'=='Debug'">
<Copy SourceFiles="$(OutDir)\$(MSBuildProjectName).pdb" DestinationFiles="..\..\CurvaLauncher\bin\$(Configuration)\$(TargetFramework)\Plugins\$(MSBuildProjectName).pdb"></Copy>
</Target>

</Project>
4 changes: 4 additions & 0 deletions src/Plugins/CurvaLauncher.Plugins.Everything/AssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
using CurvaLauncher.Plugins;
using CurvaLauncher.Plugins.Everything;

[assembly: PluginType(typeof(EverythingPlugin))]
Loading

0 comments on commit 100a1a5

Please sign in to comment.