diff --git a/csharp/Framework/ConverterOptions.cs b/csharp/Framework/ConverterOptions.cs index 089b73d..f4a4b2a 100644 --- a/csharp/Framework/ConverterOptions.cs +++ b/csharp/Framework/ConverterOptions.cs @@ -9,6 +9,7 @@ namespace OpenSvip.Framework /// /// 由 OpenSVIP Framework 提供给工程转换器的转换选项。 /// + [Serializable] public class ConverterOptions { private readonly Dictionary OptionDictionary; diff --git a/csharp/Framework/OpenSvip.Framework.csproj b/csharp/Framework/OpenSvip.Framework.csproj index 7376c03..73810d9 100644 --- a/csharp/Framework/OpenSvip.Framework.csproj +++ b/csharp/Framework/OpenSvip.Framework.csproj @@ -46,6 +46,7 @@ + diff --git a/csharp/Framework/TaskContainer.cs b/csharp/Framework/TaskContainer.cs new file mode 100644 index 0000000..d725d23 --- /dev/null +++ b/csharp/Framework/TaskContainer.cs @@ -0,0 +1,52 @@ +using System; +using System.IO; +using System.Reflection; + +namespace OpenSvip.Framework +{ + public class TaskContainer : MarshalByRefObject + { + private IProjectConverter _inputConverter; + + private IProjectConverter _outputConverter; + + private ConverterOptions _inputOptions; + + private ConverterOptions _outputOptions; + + private static IProjectConverter LoadConverter(Plugin plugin) + { + var assembly = Assembly.LoadFrom(Path.Combine(PluginManager.PluginPath, plugin.LibraryPath)); + var type = assembly.GetType(plugin.Converter); + return (IProjectConverter) Activator.CreateInstance(type); + } + + public void Init( + Plugin inputPlugin, + Plugin outputPlugin, + ConverterOptions inputOptions, + ConverterOptions outputOptions) + { + _inputConverter = LoadConverter(inputPlugin); + _outputConverter = LoadConverter(outputPlugin); + _inputOptions = inputOptions; + _outputOptions = outputOptions; + } + + public void Run(string importPath, string exportPath) + { + Warnings.AddWarning("Hello!"); + _outputConverter.Save(exportPath, _inputConverter.Load(importPath, _inputOptions), _outputOptions); + } + + public Warning[] GetWarnings() + { + return Warnings.GetWarnings(); + } + + public void ClearWarnings() + { + Warnings.ClearWarnings(); + } + } +} diff --git a/csharp/Framework/Warnings.cs b/csharp/Framework/Warnings.cs index 9085faf..af7ebd6 100644 --- a/csharp/Framework/Warnings.cs +++ b/csharp/Framework/Warnings.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.ComponentModel; using System.Reflection; @@ -27,6 +28,7 @@ public enum WarningTypes [Description("未知")] Others } + [Serializable] public class Warning { public WarningTypes Type; diff --git a/csharp/GUI/MainWindow.xaml.cs b/csharp/GUI/MainWindow.xaml.cs index 5b5b251..71c86aa 100644 --- a/csharp/GUI/MainWindow.xaml.cs +++ b/csharp/GUI/MainWindow.xaml.cs @@ -9,6 +9,7 @@ using OpenSvip.Framework; using System.Threading; using System.Diagnostics; +using System.Reflection; using Microsoft.WindowsAPICodePack.Dialogs; using System.Windows.Input; using OpenSvip.GUI.Config; @@ -197,13 +198,38 @@ private void ExecuteTasks() } new Thread(() => { + // Prepare for execution Model.ExecutionInProgress = true; - var inputConverter = PluginManager.GetConverter(Model.SelectedInputPlugin.Identifier); - var outputConverter = PluginManager.GetConverter(Model.SelectedOutputPlugin.Identifier); foreach (var task in Model.TaskList) { task.PrepareForExecution(); } + + // Construct options + var inputOptionDictionary = new Dictionary(); + foreach (var option in Model.SelectedInputOptions) + { + inputOptionDictionary[option.OptionInfo.Name] = option.OptionValue; + } + var outputOptionDictionary = new Dictionary(); + foreach (var option in Model.SelectedOutputOptions) + { + outputOptionDictionary[option.OptionInfo.Name] = option.OptionValue; + } + var inputOptions = new ConverterOptions(inputOptionDictionary); + var outputOptions = new ConverterOptions(outputOptionDictionary); + + // Create sandbox for tasks + var domain = AppDomain.CreateDomain("TaskExecution"); + var container = (TaskContainer)domain.CreateInstanceAndUnwrap( + Assembly.GetAssembly(typeof(TaskContainer)).FullName, + typeof(TaskContainer).ToString()); + container.Init( + Model.SelectedInputPlugin, + Model.SelectedOutputPlugin, + inputOptions, + outputOptions); + var skipSameFilename = Model.OverWriteOption == OverwriteOptions.Skip; var askBeforeOverwrite = Model.OverWriteOption == OverwriteOptions.Ask; foreach (var task in Model.TaskList) @@ -228,23 +254,8 @@ private void ExecuteTasks() continue; } } - - var inputOptionDictionary = new Dictionary(); - foreach (var option in Model.SelectedInputOptions) - { - inputOptionDictionary[option.OptionInfo.Name] = option.OptionValue; - } - var outputOptionDictionary = new Dictionary(); - foreach (var option in Model.SelectedOutputOptions) - { - outputOptionDictionary[option.OptionInfo.Name] = option.OptionValue; - } - outputConverter.Save( - task.ExportPath, - inputConverter.Load( - task.ImportPath, - new ConverterOptions(inputOptionDictionary)), - new ConverterOptions(outputOptionDictionary)); + // Run the container + container.Run(task.ImportPath, task.ExportPath); } catch (Exception e) { @@ -252,7 +263,7 @@ private void ExecuteTasks() task.Error = e.Message; continue; } - var warnings = Warnings.GetWarnings(); + var warnings = container.GetWarnings(); if (warnings.Any()) { task.Status = TaskStates.Warning; @@ -260,13 +271,17 @@ private void ExecuteTasks() { task.Warnings.Add(warning); } - Warnings.ClearWarnings(); + container.ClearWarnings(); } else { task.Status = TaskStates.Success; } } + // Unload the domain to release assembly files + AppDomain.Unload(domain); + + // Things after execution Model.ExecutionInProgress = false; if (!Model.OpenExportFolder) { @@ -279,27 +294,27 @@ private void ExecuteTasks() }).Start(); } - public static RelayCommand ImportCommand = new RelayCommand( + public static readonly RelayCommand ImportCommand = new RelayCommand( p => !p.Model.ExecutionInProgress, p => p.FileMaskPanel_Click(null, null)); - public static RelayCommand ExportCommand = new RelayCommand( + public static readonly RelayCommand ExportCommand = new RelayCommand( p => p.StartExecutionButton.IsEnabled, p => p.StartExecutionButton_Click(null, null)); - public static RelayCommand BrowseAndExportCommand = new RelayCommand( + public static readonly RelayCommand BrowseAndExportCommand = new RelayCommand( p => p.StartExecutionButton.IsEnabled, p => p.BrowseAndExportMenu_Click(null, null)); - public static RelayCommand ResetCommand = new RelayCommand( + public static readonly RelayCommand ResetCommand = new RelayCommand( p => !p.ExecutionInProgress, p => p.TaskList.Clear()); - public static RelayCommand AboutCommand = new RelayCommand( + public static readonly RelayCommand AboutCommand = new RelayCommand( p => true, p => p.AboutMenuItem_Click(null, null)); - public static RelayCommand ImportPluginMenuItemCommand = new RelayCommand( + public static readonly RelayCommand ImportPluginMenuItemCommand = new RelayCommand( p => { var model = (AppModel)p.DataContext; @@ -317,7 +332,7 @@ private void ExecuteTasks() ((MainWindow)App.Current.MainWindow).Model.SelectedInputPluginIndex = index; }); - public static RelayCommand ExportPluginMenuItemCommand = new RelayCommand( + public static readonly RelayCommand ExportPluginMenuItemCommand = new RelayCommand( p => true, p => { @@ -331,7 +346,7 @@ private void ExecuteTasks() ((MainWindow)App.Current.MainWindow).Model.SelectedOutputPluginIndex = index; }); - public static RelayCommand InstallPluginCommand = new RelayCommand( + public static readonly RelayCommand InstallPluginCommand = new RelayCommand( p => !p.ExecutionInProgress, p => { @@ -419,7 +434,7 @@ private void ExecuteTasks() }).Start(); }); - public static RelayCommand ManagePathsCommand = new RelayCommand( + public static readonly RelayCommand ManagePathsCommand = new RelayCommand( p => !p.ExecutionInProgress, p => PathManagerDialog.CreateDialog(p).ShowDialog());