diff --git a/ILSpy/MainWindow.xaml.cs b/ILSpy/MainWindow.xaml.cs index fc3c320a9..11a79ef1a 100644 --- a/ILSpy/MainWindow.xaml.cs +++ b/ILSpy/MainWindow.xaml.cs @@ -254,16 +254,14 @@ namespace ICSharpCode.ILSpy return true; } - void HandleCommandLineArgumentsAfterShowList(CommandLineArguments args) + async void HandleCommandLineArgumentsAfterShowList(CommandLineArguments args) { // if a SaveDirectory is given, do not start a second concurrent decompilation // by executing JumpoToReference (leads to https://github.com/icsharpcode/ILSpy/issues/710) if (!string.IsNullOrEmpty(args.SaveDirectory)) { - foreach (var x in commandLineLoadedAssemblies) { - x.ContinueWhenLoaded((Task moduleTask) => { - OnExportAssembly(moduleTask, args.SaveDirectory); - }, TaskScheduler.FromCurrentSynchronizationContext()); - } + var tasks = commandLineLoadedAssemblies.Select(a => a.GetModuleDefinitionAsync()).ToArray(); + var modules = await Task.WhenAll(tasks); + ExportAssemblies(modules, args.SaveDirectory); } else if (args.NavigateTo != null) { bool found = false; if (args.NavigateTo.StartsWith("N:", StringComparison.Ordinal)) { @@ -309,7 +307,13 @@ namespace ICSharpCode.ILSpy } commandLineLoadedAssemblies.Clear(); // clear references once we don't need them anymore } - + + void ExportAssemblies(ModuleDefinition[] modules, string path) + { + Language language = sessionSettings.FilterSettings.Language; + TextView.SaveAssembliesToDisk(language, modules.Select(m => assemblyListTreeNode.FindAssemblyNode(m)).Where(m => m != null).ToArray(), path); + } + void OnExportAssembly(Task moduleTask, string path) { AssemblyTreeNode asmNode = assemblyListTreeNode.FindAssemblyNode(moduleTask.Result); @@ -318,7 +322,7 @@ namespace ICSharpCode.ILSpy Language language = sessionSettings.FilterSettings.Language; DecompilationOptions options = new DecompilationOptions(); options.FullDecompilation = true; - options.SaveAsProjectDirectory = Path.Combine(App.CommandLineArguments.SaveDirectory, file); + options.SaveAsProjectDirectory = Path.Combine(path, file); if (!Directory.Exists(options.SaveAsProjectDirectory)) { Directory.CreateDirectory(options.SaveAsProjectDirectory); } @@ -355,7 +359,7 @@ namespace ICSharpCode.ILSpy void OpenAssemblies(ILSpySettings spySettings) { HandleCommandLineArgumentsAfterShowList(App.CommandLineArguments); - if (App.CommandLineArguments.NavigateTo == null && App.CommandLineArguments.AssembliesToLoad.Count != 1) { + if (string.IsNullOrEmpty(App.CommandLineArguments.SaveDirectory) && App.CommandLineArguments.NavigateTo == null && App.CommandLineArguments.AssembliesToLoad.Count != 1) { SharpTreeNode node = null; if (sessionSettings.ActiveTreeViewPath != null) { node = FindNodeByPath(sessionSettings.ActiveTreeViewPath, true); diff --git a/ILSpy/TextView/DecompilerTextView.cs b/ILSpy/TextView/DecompilerTextView.cs index b8fea2606..6255a918c 100644 --- a/ILSpy/TextView/DecompilerTextView.cs +++ b/ILSpy/TextView/DecompilerTextView.cs @@ -742,6 +742,57 @@ namespace ICSharpCode.ILSpy.TextView { return WholeProjectDecompiler.CleanUpFileName(text); } + + public void SaveAssembliesToDisk(ILSpy.Language language, IEnumerable treeNodes, string path) + { + RunWithCancellation( + async delegate (CancellationToken ct) { + AvalonEditTextOutput output = new AvalonEditTextOutput(); + foreach (var asmNode in treeNodes) { + ct.ThrowIfCancellationRequested(); + string asmName = CleanUpName(asmNode.LoadedAssembly.ShortName); + DecompilationOptions options = new DecompilationOptions(); + options.FullDecompilation = true; + options.SaveAsProjectDirectory = Path.Combine(path, asmName); + string fileName = Path.Combine(options.SaveAsProjectDirectory, asmName + language.ProjectFileExtension); + if (!Directory.Exists(options.SaveAsProjectDirectory)) { + Directory.CreateDirectory(options.SaveAsProjectDirectory); + } + var context = new DecompilationContext(language, new[] { asmNode }, options); + context.Options.CancellationToken = ct; + await Task.Run(delegate () { + Stopwatch stopwatch = new Stopwatch(); + stopwatch.Start(); + using (StreamWriter w = new StreamWriter(fileName)) { + try { + DecompileNodes(context, new PlainTextOutput(w)); + } catch (OperationCanceledException) { + w.WriteLine(); + w.WriteLine("Decompiled was cancelled."); + throw; + } + } + stopwatch.Stop(); + output.WriteLine("Decompilation of " + asmName + " completed in " + stopwatch.Elapsed.TotalSeconds.ToString("F1") + " seconds."); + output.WriteLine(); + output.AddButton(null, "Open Explorer", delegate { Process.Start("explorer", "/select,\"" + fileName + "\""); }); + output.WriteLine(); + output.WriteLine(); + }); + } + return output; + }) + .Then(output => ShowOutput(output)) + .Catch((Exception ex) => { + textEditor.SyntaxHighlighting = null; + Debug.WriteLine("Decompiler crashed: " + ex.ToString()); + // Unpack aggregate exceptions as long as there's only a single exception: + // (assembly load errors might produce nested aggregate exceptions) + AvalonEditTextOutput output = new AvalonEditTextOutput(); + output.WriteLine(ex.ToString()); + ShowOutput(output); + }).HandleExceptions(); + } #endregion internal ReferenceSegment GetReferenceSegmentAtMousePosition()