Skip to content
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

feat: 新的插件结构和加载逻辑, 插件项目模板 #18

Merged
merged 2 commits into from
Feb 22, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,37 +1,31 @@
<Project Sdk="Microsoft.NET.Sdk">

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

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

<!-- 自动复制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
Loading