Skip to content

Commit 100a1a5

Browse files
committed
feat: 新插件加载逻辑, 插件模板
1 parent a13bcdb commit 100a1a5

File tree

49 files changed

+418
-448
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+418
-448
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,30 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22

3+
<Import Project="..\..\Plugins\Plugin.props" />
4+
35
<PropertyGroup>
46
<OutputType>Library</OutputType>
57
<TargetFramework>net8.0-windows</TargetFramework>
68

79
<!-- 自动复制NuGet包到输出目录 -->
810
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
11+
<GenerateDependencyFile>false</GenerateDependencyFile>
912
</PropertyGroup>
1013

1114
<ItemGroup>
1215
<Compile Include="SHLoadIndirectStringList.fs" />
1316
</ItemGroup>
1417

1518
<ItemGroup>
16-
<ProjectReference Include="..\..\CurvaLauncher.Plugins\CurvaLauncher.Plugins.csproj" />
19+
<Content Include="Manifest.json">
20+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
21+
</Content>
1722
</ItemGroup>
1823

1924
<ItemGroup>
2025
<PackageReference Update="FSharp.Core" Version="8.0.101" />
2126
</ItemGroup>
2227

23-
24-
<Target Name="CopyFSharpCore" AfterTargets="Build">
25-
<Copy SourceFiles="$(OutDir)\FSharp.Core.dll" DestinationFiles="..\..\CurvaLauncher\bin\$(Configuration)\$(TargetFramework)\Libraries\FSharp.Core.dll"></Copy>
26-
</Target>
27-
28-
<Target Name="CopyOutputDebug" AfterTargets="Build" Condition="'$(Configuration)'=='Debug'">
29-
<Copy SourceFiles="$(OutDir)\$(MSBuildProjectName).dll" DestinationFiles="..\..\CurvaLauncher\bin\$(Configuration)\$(TargetFramework)\Plugins\$(MSBuildProjectName).dll"></Copy>
30-
<Copy SourceFiles="$(OutDir)\$(MSBuildProjectName).pdb" DestinationFiles="..\..\CurvaLauncher\bin\$(Configuration)\$(TargetFramework)\Plugins\$(MSBuildProjectName).pdb"></Copy>
31-
</Target>
32-
33-
<Target Name="CopyOutputRelease" AfterTargets="Build" Condition="'$(Configuration)'=='Release'">
34-
<Copy SourceFiles="$(OutDir)\$(MSBuildProjectName).dll" DestinationFiles="..\..\CurvaLauncher\bin\$(Configuration)\$(TargetFramework)\AdditionalPlugins\$(MSBuildProjectName).dll"></Copy>
35-
</Target>
28+
<Import Project="..\..\Plugins\PackAfterBuild.targets" />
3629

3730
</Project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"ID": "SHLoadIndirectStringList",
3+
"Assembly": "CurvaLauncher.Plugins.SHLoadIndirectStringList.dll"
4+
}

src/AdditionalPlugins/CurvaLauncher.Plugins.SHLoadIndirectStringList/SHLoadIndirectStringList.fs

-14
Original file line numberDiff line numberDiff line change
@@ -31,20 +31,6 @@ type public StringQueryResult(title, desc, weight) =
3131
type public SHLoadIndirectStringPlugin(context: CurvaLauncherContext) =
3232
inherit SyncPlugin(context)
3333

34-
static do
35-
AppDomain.CurrentDomain.add_AssemblyResolve(fun _ args ->
36-
let asmName = new AssemblyName(args.Name)
37-
let dllName = "FSharp.Core.dll"
38-
if asmName.Name = "FSharp.Core" then
39-
[|
40-
(Path.Combine(AppContext.BaseDirectory, dllName))
41-
(Path.Combine(AppContext.BaseDirectory, "Libraries", dllName));
42-
(Path.Combine(Directory.GetCurrentDirectory(), dllName))
43-
|].Where(File.Exists).First() |> Assembly.LoadFrom
44-
else
45-
null
46-
)
47-
4834
[<DllImport("shlwapi.dll", EntryPoint = "SHLoadIndirectString", CharSet = CharSet.Unicode, ExactSpelling = true)>]
4935
static extern uint SHLoadIndirectString(string pszSource, char& pszOutBuf, int cchOutBuf, nativeint ppvReserved)
5036

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
using System.Diagnostics;
2+
using System.IO;
3+
using System.Reflection;
4+
using System.Runtime.Loader;
5+
6+
namespace CurvaLauncher.Plugins;
7+
8+
public sealed class PluginAssemblyLoadContext : AssemblyLoadContext
9+
{
10+
private readonly AssemblyDependencyResolver resolver;
11+
12+
public PluginAssemblyLoadContext(string pluginID, string dllPath)
13+
: base($"ZipPlugin ALC - {pluginID}")
14+
{
15+
resolver = new(dllPath);
16+
}
17+
18+
protected override Assembly? Load(AssemblyName assemblyName)
19+
{
20+
string? resolvedPath = resolver.ResolveAssemblyToPath(assemblyName);
21+
return resolvedPath is not null ? LoadFromAssemblyPath(resolvedPath) : null;
22+
}
23+
24+
protected override nint LoadUnmanagedDll(string unmanagedDllName)
25+
{
26+
string? resolvedPath = resolver.ResolveUnmanagedDllToPath(unmanagedDllName);
27+
return resolvedPath is not null ? LoadUnmanagedDllFromPath(resolvedPath) : IntPtr.Zero;
28+
}
29+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
namespace CurvaLauncher.Plugins;
2+
3+
public sealed record PluginManifest(string ID, string Assembly);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
namespace CurvaLauncher.Plugins;
2+
3+
[AttributeUsage(AttributeTargets.Assembly)]
4+
public sealed class PluginTypeAttribute : Attribute
5+
{
6+
public Type PluginType { get; private set; }
7+
8+
public PluginTypeAttribute(Type pluginType)
9+
{
10+
PluginType = pluginType;
11+
}
12+
}

src/CurvaLauncher.sln

+3-13
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CurvaLauncher.Plugins.Every
3939
EndProject
4040
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{F36EDE5B-9C67-44F4-87A9-792390FECF85}"
4141
ProjectSection(SolutionItems) = preProject
42+
Plugins\CopyAfterBuild.targets = Plugins\CopyAfterBuild.targets
4243
CurvaLauncher.props = CurvaLauncher.props
44+
Plugins\PackAfterBuild.targets = Plugins\PackAfterBuild.targets
45+
Plugins\Plugin.props = Plugins\Plugin.props
4346
EndProjectSection
4447
EndProject
45-
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Templates", "Templates", "{45D0660D-436E-4419-AEB9-B6ED5BC3E0ED}"
46-
EndProject
47-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CurvaLauncher.PluginTemplate", "Templates\CurvaLauncher.PluginTemplate\CurvaLauncher.PluginTemplate.csproj", "{702E5FF3-99D0-4FD3-86E2-04C0A2E82560}"
48-
EndProject
4948
Global
5049
GlobalSection(SolutionConfigurationPlatforms) = preSolution
5150
Debug|Any CPU = Debug|Any CPU
@@ -174,14 +173,6 @@ Global
174173
{C7AC6C75-89C6-42E5-8D2A-D06994949F05}.Release|Any CPU.Build.0 = Release|Any CPU
175174
{C7AC6C75-89C6-42E5-8D2A-D06994949F05}.Release|x64.ActiveCfg = Release|x64
176175
{C7AC6C75-89C6-42E5-8D2A-D06994949F05}.Release|x64.Build.0 = Release|x64
177-
{702E5FF3-99D0-4FD3-86E2-04C0A2E82560}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
178-
{702E5FF3-99D0-4FD3-86E2-04C0A2E82560}.Debug|Any CPU.Build.0 = Debug|Any CPU
179-
{702E5FF3-99D0-4FD3-86E2-04C0A2E82560}.Debug|x64.ActiveCfg = Debug|Any CPU
180-
{702E5FF3-99D0-4FD3-86E2-04C0A2E82560}.Debug|x64.Build.0 = Debug|Any CPU
181-
{702E5FF3-99D0-4FD3-86E2-04C0A2E82560}.Release|Any CPU.ActiveCfg = Release|Any CPU
182-
{702E5FF3-99D0-4FD3-86E2-04C0A2E82560}.Release|Any CPU.Build.0 = Release|Any CPU
183-
{702E5FF3-99D0-4FD3-86E2-04C0A2E82560}.Release|x64.ActiveCfg = Release|Any CPU
184-
{702E5FF3-99D0-4FD3-86E2-04C0A2E82560}.Release|x64.Build.0 = Release|Any CPU
185176
EndGlobalSection
186177
GlobalSection(SolutionProperties) = preSolution
187178
HideSolutionNode = FALSE
@@ -198,7 +189,6 @@ Global
198189
{F3F6F783-4636-457F-80E1-CC489F524B43} = {BAACD50D-2F94-4A65-8B13-49031D617CAC}
199190
{8CFC1C29-51AA-45ED-A91F-01F513182002} = {4A86F98E-B276-4F75-9847-8D0E4280D887}
200191
{C7AC6C75-89C6-42E5-8D2A-D06994949F05} = {BAACD50D-2F94-4A65-8B13-49031D617CAC}
201-
{702E5FF3-99D0-4FD3-86E2-04C0A2E82560} = {45D0660D-436E-4419-AEB9-B6ED5BC3E0ED}
202192
EndGlobalSection
203193
GlobalSection(ExtensibilityGlobals) = postSolution
204194
SolutionGuid = {3FC4E11A-3D67-43DE-84D8-DCA1841F0D71}

src/CurvaLauncher/App.xaml.cs

+1-7
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@ private static IServiceProvider BuildServiceProvider()
5252
services.AddSingleton<HotkeyService>();
5353
services.AddSingleton<PluginService>();
5454
services.AddSingleton<ConfigService>();
55-
services.AddSingleton<LibraryService>();
5655
services.AddSingleton<ThemeService>();
5756
services.AddSingleton<I18nService>();
5857
services.AddTransient<PageService>();
@@ -81,8 +80,6 @@ protected override void OnStartup(StartupEventArgs e)
8180
.GetRequiredService<HotkeyService>();
8281
var themeService = ServiceProvider
8382
.GetRequiredService<ThemeService>();
84-
var libraryService = ServiceProvider
85-
.GetRequiredService<LibraryService>();
8683
var globalizationService = ServiceProvider
8784
.GetRequiredService<I18nService>();
8885

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

94-
// 加载库
95-
libraryService.Setup();
96-
9791
// 加载插件
9892
pluginService.LoadAllPlugins();
9993

@@ -215,7 +209,7 @@ public static void ShowLauncherWithQuery(string queryText)
215209

216210
public static void CloseLauncher()
217211
{
218-
var mainWindow =
212+
var mainWindow =
219213
ServiceProvider.GetRequiredService<MainWindow>();
220214

221215
mainWindow.ViewModel.QueryText = string.Empty;

src/CurvaLauncher/Services/LibraryService.cs

-58
This file was deleted.

src/CurvaLauncher/Services/PluginService.cs

+15-31
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,14 @@
66
using System.Linq;
77
using System.Reflection;
88
using System.Text.Json;
9-
using System.Text.Json.Nodes;
10-
using System.Text.Json.Serialization.Metadata;
119
using System.Threading.Tasks;
1210
using CommunityToolkit.Mvvm.Input;
1311
using CurvaLauncher.Models;
1412
using CurvaLauncher.Plugins;
15-
using CurvaLauncher.PluginInteraction;
1613
using System.Diagnostics;
1714
using System.IO.Compression;
1815
using System.Runtime.Loader;
16+
using IOPath = System.IO.Path;
1917

2018
namespace CurvaLauncher.Services;
2119

@@ -141,34 +139,20 @@ private bool CoreLoadZipPlugin(AppConfig config, string zipFilePath, [NotNullWhe
141139
try
142140
{
143141
using var zipFile = File.OpenRead(zipFilePath);
144-
using var zipArchive = new ZipArchive(zipFile, ZipArchiveMode.Read);
145-
var assemblyLoadContext = new AssemblyLoadContext(null, false);
146-
147-
foreach (var entry in zipArchive.Entries)
148-
{
149-
if (!entry.FullName.EndsWith(".dll", StringComparison.OrdinalIgnoreCase))
150-
{
151-
continue;
152-
}
153-
154-
using var entryStream = entry.Open();
155-
156-
try
157-
{
158-
var assembly = assemblyLoadContext.LoadFromStream(entryStream);
159-
160-
if (pluginInstance is null)
161-
{
162-
CoreLoadPluginFromAssembly(config, assembly, out pluginInstance);
163-
}
164-
}
165-
catch (Exception ex)
166-
{
167-
Debug.WriteLine($"DLL load failed, {ex}");
168-
}
169-
}
170-
171-
return pluginInstance is not null;
142+
string extractDir = IOPath.Combine(".cache", IOPath.GetFileNameWithoutExtension(zipFilePath));
143+
if (Directory.Exists(extractDir))
144+
Directory.Delete(extractDir, true);
145+
ZipFile.ExtractToDirectory(zipFile, extractDir);
146+
147+
var manifestJson = File.ReadAllText(IOPath.Combine(extractDir, "Manifest.json"));
148+
var manifest = JsonSerializer.Deserialize<PluginManifest>(manifestJson);
149+
if (manifest is null)
150+
return false;
151+
152+
var assemblyPath = IOPath.GetFullPath(IOPath.Combine(extractDir, manifest.Assembly));
153+
var alc = new PluginAssemblyLoadContext(manifest.ID, assemblyPath);
154+
Assembly assembly = alc.LoadFromAssemblyPath(assemblyPath);
155+
return CoreLoadPluginFromAssembly(config, assembly, out pluginInstance);
172156
}
173157
catch (Exception ex)
174158
{

src/Plugins/CopyAfterBuild.targets

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<Project>
2+
3+
<Target Name="CopyOutput" AfterTargets="Build">
4+
<ItemGroup>
5+
<_CompileOutput Include="$(OutputPath)\**"/>
6+
</ItemGroup>
7+
8+
<Copy SourceFiles="@(_CompileOutput)"
9+
DestinationFolder="..\..\CurvaLauncher\bin\$(Configuration)\$(TargetFramework)\Plugins\%(RecursiveDir)"
10+
SkipUnchangedFiles="true"/>
11+
</Target>
12+
13+
</Project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
using CurvaLauncher.Plugins;
2+
using CurvaLauncher.Plugins.Calculator;
3+
4+
[assembly: PluginType(typeof(CalculatorPlugin))]
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22

3+
<Import Project="..\Plugin.props" />
4+
35
<PropertyGroup>
46
<TargetFramework>net8.0-windows</TargetFramework>
57
<ImplicitUsings>enable</ImplicitUsings>
@@ -8,10 +10,6 @@
810
<EnableWindowsTargeting>true</EnableWindowsTargeting>
911
</PropertyGroup>
1012

11-
<ItemGroup>
12-
<ProjectReference Include="..\..\CurvaLauncher.Plugins\CurvaLauncher.Plugins.csproj" />
13-
</ItemGroup>
14-
1513
<ItemGroup>
1614
<Compile Update="Properties\Resources.Designer.cs">
1715
<DesignTime>True</DesignTime>
@@ -27,12 +25,6 @@
2725
</EmbeddedResource>
2826
</ItemGroup>
2927

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

34-
<Target Name="CopyOutputPdb" AfterTargets="Build" Condition="'$(Configuration)'=='Debug'">
35-
<Copy SourceFiles="$(OutDir)\$(MSBuildProjectName).pdb" DestinationFiles="..\..\CurvaLauncher\bin\$(Configuration)\$(TargetFramework)\Plugins\$(MSBuildProjectName).pdb"></Copy>
36-
</Target>
37-
3830
</Project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
using CurvaLauncher.Plugins;
2+
using CurvaLauncher.Plugins.Everything;
3+
4+
[assembly: PluginType(typeof(EverythingPlugin))]

0 commit comments

Comments
 (0)