Skip to content

Commit 2e9c5f7

Browse files
committed
修复程序集文件被占用导致插件安装失败的问题
1 parent 06b4de8 commit 2e9c5f7

File tree

5 files changed

+102
-31
lines changed

5 files changed

+102
-31
lines changed

csharp/Framework/ConverterOptions.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ namespace OpenSvip.Framework
99
/// <summary>
1010
/// 由 OpenSVIP Framework 提供给工程转换器的转换选项。
1111
/// </summary>
12+
[Serializable]
1213
public class ConverterOptions
1314
{
1415
private readonly Dictionary<string, string> OptionDictionary;

csharp/Framework/OpenSvip.Framework.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
<Compile Include="Plugin.cs" />
4747
<Compile Include="IProjectConverter.cs" />
4848
<Compile Include="PluginManager.cs" />
49+
<Compile Include="TaskContainer.cs" />
4950
<Compile Include="Properties\AssemblyInfo.cs" />
5051
<Compile Include="Warnings.cs" />
5152
</ItemGroup>

csharp/Framework/TaskContainer.cs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
using System;
2+
using System.IO;
3+
using System.Reflection;
4+
5+
namespace OpenSvip.Framework
6+
{
7+
public class TaskContainer : MarshalByRefObject
8+
{
9+
private IProjectConverter _inputConverter;
10+
11+
private IProjectConverter _outputConverter;
12+
13+
private ConverterOptions _inputOptions;
14+
15+
private ConverterOptions _outputOptions;
16+
17+
private static IProjectConverter LoadConverter(Plugin plugin)
18+
{
19+
var assembly = Assembly.LoadFrom(Path.Combine(PluginManager.PluginPath, plugin.LibraryPath));
20+
var type = assembly.GetType(plugin.Converter);
21+
return (IProjectConverter) Activator.CreateInstance(type);
22+
}
23+
24+
public void Init(
25+
Plugin inputPlugin,
26+
Plugin outputPlugin,
27+
ConverterOptions inputOptions,
28+
ConverterOptions outputOptions)
29+
{
30+
_inputConverter = LoadConverter(inputPlugin);
31+
_outputConverter = LoadConverter(outputPlugin);
32+
_inputOptions = inputOptions;
33+
_outputOptions = outputOptions;
34+
}
35+
36+
public void Run(string importPath, string exportPath)
37+
{
38+
Warnings.AddWarning("Hello!");
39+
_outputConverter.Save(exportPath, _inputConverter.Load(importPath, _inputOptions), _outputOptions);
40+
}
41+
42+
public Warning[] GetWarnings()
43+
{
44+
return Warnings.GetWarnings();
45+
}
46+
47+
public void ClearWarnings()
48+
{
49+
Warnings.ClearWarnings();
50+
}
51+
}
52+
}

csharp/Framework/Warnings.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System.Collections.Generic;
1+
using System;
2+
using System.Collections.Generic;
23
using System.ComponentModel;
34
using System.Reflection;
45

@@ -27,6 +28,7 @@ public enum WarningTypes
2728
[Description("未知")] Others
2829
}
2930

31+
[Serializable]
3032
public class Warning
3133
{
3234
public WarningTypes Type;

csharp/GUI/MainWindow.xaml.cs

Lines changed: 45 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
using OpenSvip.Framework;
1010
using System.Threading;
1111
using System.Diagnostics;
12+
using System.Reflection;
1213
using Microsoft.WindowsAPICodePack.Dialogs;
1314
using System.Windows.Input;
1415
using OpenSvip.GUI.Config;
@@ -197,13 +198,38 @@ private void ExecuteTasks()
197198
}
198199
new Thread(() =>
199200
{
201+
// Prepare for execution
200202
Model.ExecutionInProgress = true;
201-
var inputConverter = PluginManager.GetConverter(Model.SelectedInputPlugin.Identifier);
202-
var outputConverter = PluginManager.GetConverter(Model.SelectedOutputPlugin.Identifier);
203203
foreach (var task in Model.TaskList)
204204
{
205205
task.PrepareForExecution();
206206
}
207+
208+
// Construct options
209+
var inputOptionDictionary = new Dictionary<string, string>();
210+
foreach (var option in Model.SelectedInputOptions)
211+
{
212+
inputOptionDictionary[option.OptionInfo.Name] = option.OptionValue;
213+
}
214+
var outputOptionDictionary = new Dictionary<string, string>();
215+
foreach (var option in Model.SelectedOutputOptions)
216+
{
217+
outputOptionDictionary[option.OptionInfo.Name] = option.OptionValue;
218+
}
219+
var inputOptions = new ConverterOptions(inputOptionDictionary);
220+
var outputOptions = new ConverterOptions(outputOptionDictionary);
221+
222+
// Create sandbox for tasks
223+
var domain = AppDomain.CreateDomain("TaskExecution");
224+
var container = (TaskContainer)domain.CreateInstanceAndUnwrap(
225+
Assembly.GetAssembly(typeof(TaskContainer)).FullName,
226+
typeof(TaskContainer).ToString());
227+
container.Init(
228+
Model.SelectedInputPlugin,
229+
Model.SelectedOutputPlugin,
230+
inputOptions,
231+
outputOptions);
232+
207233
var skipSameFilename = Model.OverWriteOption == OverwriteOptions.Skip;
208234
var askBeforeOverwrite = Model.OverWriteOption == OverwriteOptions.Ask;
209235
foreach (var task in Model.TaskList)
@@ -228,45 +254,34 @@ private void ExecuteTasks()
228254
continue;
229255
}
230256
}
231-
232-
var inputOptionDictionary = new Dictionary<string, string>();
233-
foreach (var option in Model.SelectedInputOptions)
234-
{
235-
inputOptionDictionary[option.OptionInfo.Name] = option.OptionValue;
236-
}
237-
var outputOptionDictionary = new Dictionary<string, string>();
238-
foreach (var option in Model.SelectedOutputOptions)
239-
{
240-
outputOptionDictionary[option.OptionInfo.Name] = option.OptionValue;
241-
}
242-
outputConverter.Save(
243-
task.ExportPath,
244-
inputConverter.Load(
245-
task.ImportPath,
246-
new ConverterOptions(inputOptionDictionary)),
247-
new ConverterOptions(outputOptionDictionary));
257+
// Run the container
258+
container.Run(task.ImportPath, task.ExportPath);
248259
}
249260
catch (Exception e)
250261
{
251262
task.Status = TaskStates.Error;
252263
task.Error = e.Message;
253264
continue;
254265
}
255-
var warnings = Warnings.GetWarnings();
266+
var warnings = container.GetWarnings();
256267
if (warnings.Any())
257268
{
258269
task.Status = TaskStates.Warning;
259270
foreach (var warning in warnings)
260271
{
261272
task.Warnings.Add(warning);
262273
}
263-
Warnings.ClearWarnings();
274+
container.ClearWarnings();
264275
}
265276
else
266277
{
267278
task.Status = TaskStates.Success;
268279
}
269280
}
281+
// Unload the domain to release assembly files
282+
AppDomain.Unload(domain);
283+
284+
// Things after execution
270285
Model.ExecutionInProgress = false;
271286
if (!Model.OpenExportFolder)
272287
{
@@ -279,27 +294,27 @@ private void ExecuteTasks()
279294
}).Start();
280295
}
281296

282-
public static RelayCommand<MainWindow> ImportCommand = new RelayCommand<MainWindow>(
297+
public static readonly RelayCommand<MainWindow> ImportCommand = new RelayCommand<MainWindow>(
283298
p => !p.Model.ExecutionInProgress,
284299
p => p.FileMaskPanel_Click(null, null));
285300

286-
public static RelayCommand<MainWindow> ExportCommand = new RelayCommand<MainWindow>(
301+
public static readonly RelayCommand<MainWindow> ExportCommand = new RelayCommand<MainWindow>(
287302
p => p.StartExecutionButton.IsEnabled,
288303
p => p.StartExecutionButton_Click(null, null));
289304

290-
public static RelayCommand<MainWindow> BrowseAndExportCommand = new RelayCommand<MainWindow>(
305+
public static readonly RelayCommand<MainWindow> BrowseAndExportCommand = new RelayCommand<MainWindow>(
291306
p => p.StartExecutionButton.IsEnabled,
292307
p => p.BrowseAndExportMenu_Click(null, null));
293308

294-
public static RelayCommand<AppModel> ResetCommand = new RelayCommand<AppModel>(
309+
public static readonly RelayCommand<AppModel> ResetCommand = new RelayCommand<AppModel>(
295310
p => !p.ExecutionInProgress,
296311
p => p.TaskList.Clear());
297312

298-
public static RelayCommand<MainWindow> AboutCommand = new RelayCommand<MainWindow>(
313+
public static readonly RelayCommand<MainWindow> AboutCommand = new RelayCommand<MainWindow>(
299314
p => true,
300315
p => p.AboutMenuItem_Click(null, null));
301316

302-
public static RelayCommand<System.Windows.Controls.MenuItem> ImportPluginMenuItemCommand = new RelayCommand<System.Windows.Controls.MenuItem>(
317+
public static readonly RelayCommand<System.Windows.Controls.MenuItem> ImportPluginMenuItemCommand = new RelayCommand<System.Windows.Controls.MenuItem>(
303318
p =>
304319
{
305320
var model = (AppModel)p.DataContext;
@@ -317,7 +332,7 @@ private void ExecuteTasks()
317332
((MainWindow)App.Current.MainWindow).Model.SelectedInputPluginIndex = index;
318333
});
319334

320-
public static RelayCommand<System.Windows.Controls.MenuItem> ExportPluginMenuItemCommand = new RelayCommand<System.Windows.Controls.MenuItem>(
335+
public static readonly RelayCommand<System.Windows.Controls.MenuItem> ExportPluginMenuItemCommand = new RelayCommand<System.Windows.Controls.MenuItem>(
321336
p => true,
322337
p =>
323338
{
@@ -331,7 +346,7 @@ private void ExecuteTasks()
331346
((MainWindow)App.Current.MainWindow).Model.SelectedOutputPluginIndex = index;
332347
});
333348

334-
public static RelayCommand<AppModel> InstallPluginCommand = new RelayCommand<AppModel>(
349+
public static readonly RelayCommand<AppModel> InstallPluginCommand = new RelayCommand<AppModel>(
335350
p => !p.ExecutionInProgress,
336351
p =>
337352
{
@@ -419,7 +434,7 @@ private void ExecuteTasks()
419434
}).Start();
420435
});
421436

422-
public static RelayCommand<AppModel> ManagePathsCommand = new RelayCommand<AppModel>(
437+
public static readonly RelayCommand<AppModel> ManagePathsCommand = new RelayCommand<AppModel>(
423438
p => !p.ExecutionInProgress,
424439
p => PathManagerDialog.CreateDialog(p).ShowDialog());
425440

0 commit comments

Comments
 (0)