diff --git a/ICSharpCode.Decompiler/CSharp/WholeProjectDecompiler.cs b/ICSharpCode.Decompiler/CSharp/WholeProjectDecompiler.cs
index 6ec5d6802..377a617d5 100644
--- a/ICSharpCode.Decompiler/CSharp/WholeProjectDecompiler.cs
+++ b/ICSharpCode.Decompiler/CSharp/WholeProjectDecompiler.cs
@@ -35,6 +35,7 @@ using System.Reflection.Metadata;
using static ICSharpCode.Decompiler.Metadata.DotNetCorePathFinderExtensions;
using static ICSharpCode.Decompiler.Metadata.MetadataExtensions;
using ICSharpCode.Decompiler.Metadata;
+using ICSharpCode.Decompiler.Solution;
namespace ICSharpCode.Decompiler.CSharp
{
diff --git a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
index 6efca3120..afb73dcf4 100644
--- a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
+++ b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
@@ -61,7 +61,9 @@
-
+
+
+
diff --git a/ICSharpCode.Decompiler/Solution/ProjectId.cs b/ICSharpCode.Decompiler/Solution/ProjectId.cs
new file mode 100644
index 000000000..65a4e8d9e
--- /dev/null
+++ b/ICSharpCode.Decompiler/Solution/ProjectId.cs
@@ -0,0 +1,56 @@
+// Copyright (c) 2019 AlphaSierraPapa for the SharpDevelop Team
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this
+// software and associated documentation files (the "Software"), to deal in the Software
+// without restriction, including without limitation the rights to use, copy, modify, merge,
+// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
+// to whom the Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all copies or
+// substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+
+using System;
+
+namespace ICSharpCode.Decompiler.Solution
+{
+ ///
+ /// A container class that holds platform and GUID information about a Visual Studio project.
+ ///
+ public class ProjectId
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The project platform.
+ /// The project GUID.
+ ///
+ /// Thrown when
+ /// or is null or empty.
+ public ProjectId(string projectPlatform, Guid projectGuid)
+ {
+ if (string.IsNullOrWhiteSpace(projectPlatform)) {
+ throw new ArgumentException("The platform cannot be null or empty.", nameof(projectPlatform));
+ }
+
+ Guid = projectGuid;
+ PlatformName = projectPlatform;
+ }
+
+ ///
+ /// Gets the GUID of this project.
+ ///
+ public Guid Guid { get; }
+
+ ///
+ /// Gets the platform name of this project. Only single platform per project is supported.
+ ///
+ public string PlatformName { get; }
+ }
+}
diff --git a/ICSharpCode.Decompiler/Solution/ProjectItem.cs b/ICSharpCode.Decompiler/Solution/ProjectItem.cs
new file mode 100644
index 000000000..bf1222368
--- /dev/null
+++ b/ICSharpCode.Decompiler/Solution/ProjectItem.cs
@@ -0,0 +1,55 @@
+// Copyright (c) 2019 AlphaSierraPapa for the SharpDevelop Team
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this
+// software and associated documentation files (the "Software"), to deal in the Software
+// without restriction, including without limitation the rights to use, copy, modify, merge,
+// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
+// to whom the Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all copies or
+// substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+
+using System;
+using System.IO;
+
+namespace ICSharpCode.Decompiler.Solution
+{
+ ///
+ /// A container class that holds information about a Visual Studio project.
+ ///
+ public sealed class ProjectItem : ProjectId
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The full path of the project file.
+ /// The project platform.
+ /// The project GUID.
+ ///
+ /// Thrown when
+ /// or is null or empty.
+ public ProjectItem(string projectFile, string projectPlatform, Guid projectGuid)
+ : base(projectPlatform, projectGuid)
+ {
+ ProjectName = Path.GetFileNameWithoutExtension(projectFile);
+ FilePath = projectFile;
+ }
+
+ ///
+ /// Gets the name of the project.
+ ///
+ public string ProjectName { get; }
+
+ ///
+ /// Gets the full path to the project file.
+ ///
+ public string FilePath { get; }
+ }
+}
diff --git a/ICSharpCode.Decompiler/CSharp/SolutionCreator.cs b/ICSharpCode.Decompiler/Solution/SolutionCreator.cs
similarity index 78%
rename from ICSharpCode.Decompiler/CSharp/SolutionCreator.cs
rename to ICSharpCode.Decompiler/Solution/SolutionCreator.cs
index 7c3f26e0e..fc63beca5 100644
--- a/ICSharpCode.Decompiler/CSharp/SolutionCreator.cs
+++ b/ICSharpCode.Decompiler/Solution/SolutionCreator.cs
@@ -1,4 +1,4 @@
-// Copyright (c) 2016 Daniel Grunwald
+// Copyright (c) 2019 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
@@ -22,74 +22,8 @@ using System.IO;
using System.Linq;
using System.Xml.Linq;
-namespace ICSharpCode.Decompiler.CSharp
+namespace ICSharpCode.Decompiler.Solution
{
- ///
- /// A container class that holds information about a Visual Studio project.
- ///
- public sealed class ProjectItem : ProjectId
- {
- ///
- /// Initializes a new instance of the class.
- ///
- /// The full path of the project file.
- /// The project platform.
- /// The project GUID.
- ///
- /// Thrown when
- /// or is null or empty.
- public ProjectItem(string projectFile, string projectPlatform, Guid projectGuid)
- : base(projectPlatform, projectGuid)
- {
- ProjectName = Path.GetFileNameWithoutExtension(projectFile);
- FilePath = projectFile;
- }
-
- ///
- /// Gets the name of the project.
- ///
- public string ProjectName { get; }
-
- ///
- /// Gets the full path to the project file.
- ///
- public string FilePath { get; }
- }
-
- ///
- /// A container class that holds platform and GUID information about a Visual Studio project.
- ///
- public class ProjectId
- {
- ///
- /// Initializes a new instance of the class.
- ///
- /// The project platform.
- /// The project GUID.
- ///
- /// Thrown when
- /// or is null or empty.
- public ProjectId(string projectPlatform, Guid projectGuid)
- {
- if (string.IsNullOrWhiteSpace(projectPlatform)) {
- throw new ArgumentException("The platform cannot be null or empty.", nameof(projectPlatform));
- }
-
- Guid = projectGuid;
- PlatformName = projectPlatform;
- }
-
- ///
- /// Gets the GUID of this project.
- ///
- public Guid Guid { get; }
-
- ///
- /// Gets the platform name of this project. Only single platform per project is supported.
- ///
- public string PlatformName { get; }
- }
-
///
/// A helper class that can write a Visual Studio Solution file for the provided projects.
///
diff --git a/ILSpy/Languages/CSharpLanguage.cs b/ILSpy/Languages/CSharpLanguage.cs
index 57cab0ee8..35f614764 100644
--- a/ILSpy/Languages/CSharpLanguage.cs
+++ b/ILSpy/Languages/CSharpLanguage.cs
@@ -34,6 +34,7 @@ using ICSharpCode.Decompiler.CSharp.Syntax;
using ICSharpCode.Decompiler.CSharp.Transforms;
using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.Output;
+using ICSharpCode.Decompiler.Solution;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.Util;
using ICSharpCode.ILSpy.TreeNodes;
@@ -343,7 +344,7 @@ namespace ICSharpCode.ILSpy
}
}
- public override object DecompileAssembly(LoadedAssembly assembly, ITextOutput output, DecompilationOptions options)
+ public override ProjectId DecompileAssembly(LoadedAssembly assembly, ITextOutput output, DecompilationOptions options)
{
var module = assembly.GetPEFileOrNull();
if (options.FullDecompilation && options.SaveAsProjectDirectory != null) {
@@ -389,7 +390,7 @@ namespace ICSharpCode.ILSpy
}
if (metadata.IsAssembly) {
var asm = metadata.GetAssemblyDefinition();
- if (asm.HashAlgorithm != System.Reflection.AssemblyHashAlgorithm.None)
+ if (asm.HashAlgorithm != AssemblyHashAlgorithm.None)
output.WriteLine("// Hash algorithm: " + asm.HashAlgorithm.ToString().ToUpper());
if (!asm.PublicKey.IsNil) {
output.Write("// Public key: ");
@@ -415,8 +416,7 @@ namespace ICSharpCode.ILSpy
}
WriteCode(output, options.DecompilerSettings, st, decompiler.TypeSystem);
}
-
- return true;
+ return null;
}
}
diff --git a/ILSpy/Languages/ILLanguage.cs b/ILSpy/Languages/ILLanguage.cs
index da26caeb2..3dd1ec1ab 100644
--- a/ILSpy/Languages/ILLanguage.cs
+++ b/ILSpy/Languages/ILLanguage.cs
@@ -27,6 +27,8 @@ using System.Reflection.Metadata.Ecma335;
using System.Linq;
using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.TypeSystem;
+using ICSharpCode.Decompiler.Util;
+using ICSharpCode.Decompiler.Solution;
namespace ICSharpCode.ILSpy
{
@@ -150,7 +152,7 @@ namespace ICSharpCode.ILSpy
dis.DisassembleNamespace(nameSpace, module, types.Select(t => (TypeDefinitionHandle)t.MetadataToken));
}
- public override object DecompileAssembly(LoadedAssembly assembly, ITextOutput output, DecompilationOptions options)
+ public override ProjectId DecompileAssembly(LoadedAssembly assembly, ITextOutput output, DecompilationOptions options)
{
output.WriteLine("// " + assembly.FileName);
output.WriteLine();
@@ -174,8 +176,7 @@ namespace ICSharpCode.ILSpy
dis.WriteModuleContents(module);
}
}
-
- return true;
+ return null;
}
}
}
diff --git a/ILSpy/Languages/Language.cs b/ILSpy/Languages/Language.cs
index 76f435244..e97696fea 100644
--- a/ILSpy/Languages/Language.cs
+++ b/ILSpy/Languages/Language.cs
@@ -23,6 +23,7 @@ using System.Reflection.PortableExecutable;
using System.Text;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.Metadata;
+using ICSharpCode.Decompiler.Solution;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.TypeSystem.Implementation;
using ICSharpCode.Decompiler.Util;
@@ -131,11 +132,11 @@ namespace ICSharpCode.ILSpy
WriteCommentLine(output, nameSpace);
}
- public virtual object DecompileAssembly(LoadedAssembly assembly, ITextOutput output, DecompilationOptions options)
+ public virtual ProjectId DecompileAssembly(LoadedAssembly assembly, ITextOutput output, DecompilationOptions options)
{
WriteCommentLine(output, assembly.FileName);
var asm = assembly.GetPEFileOrNull();
- if (asm == null) return false;
+ if (asm == null) return null;
var metadata = asm.Metadata;
if (metadata.IsAssembly) {
var name = metadata.GetAssemblyDefinition();
@@ -147,8 +148,7 @@ namespace ICSharpCode.ILSpy
} else {
WriteCommentLine(output, metadata.GetString(metadata.GetModuleDefinition().Name));
}
-
- return true;
+ return null;
}
public virtual void WriteCommentLine(ITextOutput output, string comment)
diff --git a/ILSpy/MainWindow.xaml.cs b/ILSpy/MainWindow.xaml.cs
index 238c74307..fe7c45374 100644
--- a/ILSpy/MainWindow.xaml.cs
+++ b/ILSpy/MainWindow.xaml.cs
@@ -914,29 +914,80 @@ namespace ICSharpCode.ILSpy
void SaveCommandExecuted(object sender, ExecutedRoutedEventArgs e)
{
var selectedNodes = SelectedNodes.ToList();
- if (selectedNodes.Count > 1) {
- var assemblyNodes = selectedNodes
- .OfType()
- .Where(n => n.Language is CSharpLanguage)
- .ToList();
-
- if (assemblyNodes.Count == selectedNodes.Count) {
- var initialPath = Path.GetDirectoryName(assemblyNodes[0].LoadedAssembly.FileName);
- var selectedPath = SolutionWriter.SelectSolutionFile(initialPath);
-
- if (!string.IsNullOrEmpty(selectedPath)) {
- SolutionWriter.CreateSolution(TextView, selectedPath, assemblyNodes);
- }
+ if (selectedNodes.Count == 1) {
+ // if there's only one treenode selected
+ // we will invoke the custom Save logic
+ if (selectedNodes[0].Save(TextView))
return;
+ } else if (selectedNodes.All(n => n is AssemblyTreeNode)) {
+ var initialPath = Path.GetDirectoryName(((AssemblyTreeNode)selectedNodes[0]).LoadedAssembly.FileName);
+ var selectedPath = SelectSolutionFile(initialPath);
+
+ if (!string.IsNullOrEmpty(selectedPath)) {
+ var assemblies = selectedNodes.OfType()
+ .Select(n => n.LoadedAssembly)
+ .Where(a => a != null).ToArray();
+ SolutionWriter.CreateSolution(TextView, selectedPath, CurrentLanguage, assemblies);
}
+ return;
}
- if (selectedNodes.Count != 1 || !selectedNodes[0].Save(TextView)) {
- var options = new DecompilationOptions() { FullDecompilation = true };
- TextView.SaveToDisk(CurrentLanguage, selectedNodes, options);
+ // Fallback: if nobody was able to handle the request, use default behavior.
+ // try to save all nodes to disk.
+ var options = new DecompilationOptions() { FullDecompilation = true };
+ TextView.SaveToDisk(CurrentLanguage, selectedNodes, options);
+ }
+
+ ///
+ /// Shows a File Selection dialog where the user can select the target file for the solution.
+ ///
+ /// The initial path to show in the dialog. If not specified, the 'Documents' directory
+ /// will be used.
+ ///
+ /// The full path of the selected target file, or null if the user canceled.
+ string SelectSolutionFile(string path)
+ {
+ const string SolutionExtension = ".sln";
+ const string DefaultSolutionName = "Solution";
+
+ if (string.IsNullOrWhiteSpace(path)) {
+ path = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
}
+
+ SaveFileDialog dlg = new SaveFileDialog();
+ dlg.InitialDirectory = path;
+ dlg.FileName = Path.Combine(path, DefaultSolutionName + SolutionExtension);
+ dlg.Filter = "Visual Studio Solution file|*" + SolutionExtension;
+
+ bool targetInvalid;
+ do {
+ if (dlg.ShowDialog() != true) {
+ return null;
+ }
+
+ string selectedPath = Path.GetDirectoryName(dlg.FileName);
+ try {
+ targetInvalid = Directory.EnumerateFileSystemEntries(selectedPath).Any();
+ } catch (Exception e) when (e is IOException || e is UnauthorizedAccessException || e is System.Security.SecurityException) {
+ MessageBox.Show(
+ "The directory cannot be accessed. Please ensure it exists and you have sufficient rights to access it.",
+ "Solution directory not accessible",
+ MessageBoxButton.OK, MessageBoxImage.Error);
+ targetInvalid = true;
+ continue;
+ }
+
+ if (targetInvalid) {
+ MessageBox.Show(
+ "The directory is not empty. Please select an empty directory.",
+ "Solution directory not empty",
+ MessageBoxButton.OK, MessageBoxImage.Warning);
+ }
+ } while (targetInvalid);
+
+ return dlg.FileName;
}
-
+
public void RefreshDecompiledView()
{
try {
diff --git a/ILSpy/SolutionWriter.cs b/ILSpy/SolutionWriter.cs
index 45fd3ce67..d892e22ec 100644
--- a/ILSpy/SolutionWriter.cs
+++ b/ILSpy/SolutionWriter.cs
@@ -22,15 +22,12 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
-using System.Security;
using System.Threading;
using System.Threading.Tasks;
-using System.Windows;
using ICSharpCode.Decompiler;
-using ICSharpCode.Decompiler.CSharp;
+using ICSharpCode.Decompiler.Solution;
+using ICSharpCode.Decompiler.Util;
using ICSharpCode.ILSpy.TextView;
-using ICSharpCode.ILSpy.TreeNodes;
-using Microsoft.Win32;
namespace ICSharpCode.ILSpy
{
@@ -38,73 +35,23 @@ namespace ICSharpCode.ILSpy
/// An utility class that creates a Visual Studio solution containing projects for the
/// decompiled assemblies.
///
- internal static class SolutionWriter
+ internal class SolutionWriter
{
- private const string SolutionExtension = ".sln";
- private const string DefaultSolutionName = "Solution";
-
- ///
- /// Shows a File Selection dialog where the user can select the target file for the solution.
- ///
- /// The initial path to show in the dialog. If not specified, the 'Documents' directory
- /// will be used.
- ///
- /// The full path of the selected target file, or null if the user canceled.
- public static string SelectSolutionFile(string path)
- {
- if (string.IsNullOrWhiteSpace(path)) {
- path = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
- }
-
- SaveFileDialog dlg = new SaveFileDialog();
- dlg.InitialDirectory = path;
- dlg.FileName = Path.Combine(path, DefaultSolutionName + SolutionExtension);
- dlg.Filter = "Visual Studio Solution file|*" + SolutionExtension;
-
- bool targetInvalid;
- do {
- if (dlg.ShowDialog() != true) {
- return null;
- }
-
- string selectedPath = Path.GetDirectoryName(dlg.FileName);
- try {
- targetInvalid = Directory.EnumerateFileSystemEntries(selectedPath).Any();
- } catch (Exception e) when (e is IOException || e is UnauthorizedAccessException || e is SecurityException) {
- MessageBox.Show(
- "The directory cannot be accessed. Please ensure it exists and you have sufficient rights to access it.",
- "Solution directory not accessible",
- MessageBoxButton.OK, MessageBoxImage.Error);
- targetInvalid = true;
- continue;
- }
-
- if (targetInvalid) {
- MessageBox.Show(
- "The directory is not empty. Please select an empty directory.",
- "Solution directory not empty",
- MessageBoxButton.OK, MessageBoxImage.Warning);
- }
- } while (targetInvalid);
-
- return dlg.FileName;
- }
-
///
/// Creates a Visual Studio solution that contains projects with decompiled code
- /// of the specified . The solution file will be saved
+ /// of the specified . The solution file will be saved
/// to the . The directory of this file must either
/// be empty or not exist.
///
/// A reference to the instance.
/// The target file path of the solution file.
- /// The assembly nodes to decompile.
+ /// The assembly nodes to decompile.
///
/// Thrown when is null,
/// an empty or a whitespace string.
/// Thrown when > or
- /// is null.
- public static void CreateSolution(DecompilerTextView textView, string solutionFilePath, IEnumerable assemblyNodes)
+ /// is null.
+ public static void CreateSolution(DecompilerTextView textView, string solutionFilePath, Language language, IEnumerable assemblies)
{
if (textView == null) {
throw new ArgumentNullException(nameof(textView));
@@ -114,29 +61,37 @@ namespace ICSharpCode.ILSpy
throw new ArgumentException("The solution file path cannot be null or empty.", nameof(solutionFilePath));
}
- if (assemblyNodes == null) {
- throw new ArgumentNullException(nameof(assemblyNodes));
+ if (assemblies == null) {
+ throw new ArgumentNullException(nameof(assemblies));
}
+ var writer = new SolutionWriter(solutionFilePath);
+
textView
- .RunWithCancellation(ct => CreateSolution(solutionFilePath, assemblyNodes, ct))
+ .RunWithCancellation(ct => writer.CreateSolution(assemblies, language, ct))
.Then(output => textView.ShowText(output))
.HandleExceptions();
}
- private static async Task CreateSolution(
- string solutionFilePath,
- IEnumerable assemblyNodes,
- CancellationToken ct)
+ readonly string solutionFilePath;
+ readonly string solutionDirectory;
+ readonly ConcurrentBag projects;
+ readonly ConcurrentBag statusOutput;
+
+ SolutionWriter(string solutionFilePath)
{
- var solutionDirectory = Path.GetDirectoryName(solutionFilePath);
- var statusOutput = new ConcurrentBag();
- var projects = new ConcurrentBag();
+ this.solutionFilePath = solutionFilePath;
+ solutionDirectory = Path.GetDirectoryName(solutionFilePath);
+ statusOutput = new ConcurrentBag();
+ projects = new ConcurrentBag();
+ }
+ async Task CreateSolution(IEnumerable assemblies, Language language, CancellationToken ct)
+ {
var result = new AvalonEditTextOutput();
var duplicates = new HashSet();
- if (assemblyNodes.Any(n => !duplicates.Add(n.LoadedAssembly.ShortName))) {
+ if (assemblies.Any(asm => !duplicates.Add(asm.ShortName))) {
result.WriteLine("Duplicate assembly names selected, cannot generate a solution.");
return result;
}
@@ -144,7 +99,7 @@ namespace ICSharpCode.ILSpy
Stopwatch stopwatch = Stopwatch.StartNew();
try {
- await Task.Run(() => Parallel.ForEach(assemblyNodes, n => WriteProject(n, solutionDirectory, statusOutput, projects, ct)))
+ await Task.Run(() => Parallel.ForEach(assemblies, n => WriteProject(n, language, solutionDirectory, ct)))
.ConfigureAwait(false);
await Task.Run(() => SolutionCreator.WriteSolutionFile(solutionFilePath, projects))
@@ -162,7 +117,7 @@ namespace ICSharpCode.ILSpy
result.WriteLine(e.Message);
return true;
});
-
+
return result;
}
@@ -172,13 +127,13 @@ namespace ICSharpCode.ILSpy
if (statusOutput.Count == 0) {
result.WriteLine("Successfully decompiled the following assemblies into Visual Studio projects:");
- foreach (var item in assemblyNodes.Select(n => n.Text.ToString())) {
+ foreach (var item in assemblies.Select(n => n.Text.ToString())) {
result.WriteLine(item);
}
result.WriteLine();
- if (assemblyNodes.Count() == projects.Count) {
+ if (assemblies.Count() == projects.Count) {
result.WriteLine("Created the Visual Studio Solution file.");
}
@@ -191,17 +146,10 @@ namespace ICSharpCode.ILSpy
return result;
}
- private static void WriteProject(
- AssemblyTreeNode assemblyNode,
- string targetDirectory,
- ConcurrentBag statusOutput,
- ConcurrentBag targetContainer,
- CancellationToken ct)
+ void WriteProject(LoadedAssembly loadedAssembly, Language language, string targetDirectory, CancellationToken ct)
{
- var loadedAssembly = assemblyNode.LoadedAssembly;
-
targetDirectory = Path.Combine(targetDirectory, loadedAssembly.ShortName);
- string projectFileName = Path.Combine(targetDirectory, loadedAssembly.ShortName + assemblyNode.Language.ProjectFileExtension);
+ string projectFileName = Path.Combine(targetDirectory, loadedAssembly.ShortName + language.ProjectFileExtension);
if (!Directory.Exists(targetDirectory)) {
try {
@@ -214,21 +162,19 @@ namespace ICSharpCode.ILSpy
try {
using (var projectFileWriter = new StreamWriter(projectFileName)) {
- var projectFileOutput = new PlainTextOutput(projectFileWriter);
- var options = new DecompilationOptions() {
- FullDecompilation = true,
- CancellationToken = ct,
- SaveAsProjectDirectory = targetDirectory };
-
- if (assemblyNode.Decompile(assemblyNode.Language, projectFileOutput, options) is ProjectId projectInfo) {
- targetContainer.Add(new ProjectItem(projectFileName, projectInfo.PlatformName, projectInfo.Guid));
+ var projectFileOutput = new PlainTextOutput(projectFileWriter);
+ var options = new DecompilationOptions() {
+ FullDecompilation = true,
+ CancellationToken = ct,
+ SaveAsProjectDirectory = targetDirectory
+ };
+
+ var projectInfo = language.DecompileAssembly(loadedAssembly, projectFileOutput, options);
+ if (projectInfo != null) {
+ projects.Add(new ProjectItem(projectFileName, projectInfo.PlatformName, projectInfo.Guid));
}
}
- }
- catch (OperationCanceledException) {
- throw;
- }
- catch (Exception e) {
+ } catch (Exception e) when (!(e is OperationCanceledException)) {
statusOutput.Add($"Failed to decompile the assembly '{loadedAssembly.FileName}':{Environment.NewLine}{e}");
}
}
diff --git a/ILSpy/TreeNodes/AssemblyListTreeNode.cs b/ILSpy/TreeNodes/AssemblyListTreeNode.cs
index 3b8e5a519..e53a3a883 100644
--- a/ILSpy/TreeNodes/AssemblyListTreeNode.cs
+++ b/ILSpy/TreeNodes/AssemblyListTreeNode.cs
@@ -141,7 +141,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
public Action Select = delegate { };
- public override object Decompile(Language language, ITextOutput output, DecompilationOptions options)
+ public override void Decompile(Language language, ITextOutput output, DecompilationOptions options)
{
language.WriteCommentLine(output, "List: " + assemblyList.ListName);
output.WriteLine();
@@ -150,8 +150,6 @@ namespace ICSharpCode.ILSpy.TreeNodes
output.WriteLine();
asm.Decompile(language, output, options);
}
-
- return true;
}
#region Find*Node
diff --git a/ILSpy/TreeNodes/AssemblyReferenceTreeNode.cs b/ILSpy/TreeNodes/AssemblyReferenceTreeNode.cs
index 192820246..8aa8f8c0d 100644
--- a/ILSpy/TreeNodes/AssemblyReferenceTreeNode.cs
+++ b/ILSpy/TreeNodes/AssemblyReferenceTreeNode.cs
@@ -79,7 +79,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
}
}
- public override object Decompile(Language language, ITextOutput output, DecompilationOptions options)
+ public override void Decompile(Language language, ITextOutput output, DecompilationOptions options)
{
var loaded = parentAssembly.LoadedAssembly.LoadedAssemblyReferencesInfo.TryGetInfo(r.FullName, out var info);
if (r.IsWindowsRuntime) {
@@ -98,8 +98,6 @@ namespace ICSharpCode.ILSpy.TreeNodes
output.Unindent();
output.WriteLine();
}
-
- return true;
}
}
}
diff --git a/ILSpy/TreeNodes/AssemblyTreeNode.cs b/ILSpy/TreeNodes/AssemblyTreeNode.cs
index 39669c15f..60f34e6b2 100644
--- a/ILSpy/TreeNodes/AssemblyTreeNode.cs
+++ b/ILSpy/TreeNodes/AssemblyTreeNode.cs
@@ -240,7 +240,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
return FilterResult.Recurse;
}
- public override object Decompile(Language language, ITextOutput output, DecompilationOptions options)
+ public override void Decompile(Language language, ITextOutput output, DecompilationOptions options)
{
void HandleException(Exception ex, string message)
{
@@ -259,21 +259,21 @@ namespace ICSharpCode.ILSpy.TreeNodes
switch (ex.InnerException) {
case BadImageFormatException badImage:
HandleException(badImage, "This file does not contain a managed assembly.");
- return null;
+ return;
case FileNotFoundException fileNotFound:
HandleException(fileNotFound, "The file was not found.");
- return null;
+ return;
case DirectoryNotFoundException dirNotFound:
HandleException(dirNotFound, "The directory was not found.");
- return null;
+ return;
case PEFileNotSupportedException notSupported:
HandleException(notSupported, notSupported.Message);
- return null;
+ return;
default:
throw;
}
}
- return language.DecompileAssembly(LoadedAssembly, output, options);
+ language.DecompileAssembly(LoadedAssembly, output, options);
}
public override bool Save(DecompilerTextView textView)
diff --git a/ILSpy/TreeNodes/BaseTypesEntryNode.cs b/ILSpy/TreeNodes/BaseTypesEntryNode.cs
index 41edd0f8c..3c96c40dd 100644
--- a/ILSpy/TreeNodes/BaseTypesEntryNode.cs
+++ b/ILSpy/TreeNodes/BaseTypesEntryNode.cs
@@ -97,10 +97,9 @@ namespace ICSharpCode.ILSpy.TreeNodes
return false;
}
- public override object Decompile(Language language, ITextOutput output, DecompilationOptions options)
+ public override void Decompile(Language language, ITextOutput output, DecompilationOptions options)
{
language.WriteCommentLine(output, language.TypeToString(type, includeNamespace: true));
- return true;
}
IEntity IMemberTreeNode.Member {
diff --git a/ILSpy/TreeNodes/BaseTypesTreeNode.cs b/ILSpy/TreeNodes/BaseTypesTreeNode.cs
index 58565a938..8cbdb2304 100644
--- a/ILSpy/TreeNodes/BaseTypesTreeNode.cs
+++ b/ILSpy/TreeNodes/BaseTypesTreeNode.cs
@@ -69,14 +69,12 @@ namespace ICSharpCode.ILSpy.TreeNodes
}
}
- public override object Decompile(Language language, ITextOutput output, DecompilationOptions options)
+ public override void Decompile(Language language, ITextOutput output, DecompilationOptions options)
{
App.Current.Dispatcher.Invoke(DispatcherPriority.Normal, new Action(EnsureLazyChildren));
foreach (ILSpyTreeNode child in this.Children) {
child.Decompile(language, output, options);
}
-
- return true;
}
}
}
\ No newline at end of file
diff --git a/ILSpy/TreeNodes/DerivedTypesEntryNode.cs b/ILSpy/TreeNodes/DerivedTypesEntryNode.cs
index f3d9fe29f..91da3e033 100644
--- a/ILSpy/TreeNodes/DerivedTypesEntryNode.cs
+++ b/ILSpy/TreeNodes/DerivedTypesEntryNode.cs
@@ -90,10 +90,9 @@ namespace ICSharpCode.ILSpy.TreeNodes
e.Handled = BaseTypesEntryNode.ActivateItem(this, type);
}
- public override object Decompile(Language language, ITextOutput output, DecompilationOptions options)
+ public override void Decompile(Language language, ITextOutput output, DecompilationOptions options)
{
language.WriteCommentLine(output, language.TypeToString(type, includeNamespace: true));
- return true;
}
IEntity IMemberTreeNode.Member => type;
diff --git a/ILSpy/TreeNodes/DerivedTypesTreeNode.cs b/ILSpy/TreeNodes/DerivedTypesTreeNode.cs
index 8518e08e3..3b6e50a30 100644
--- a/ILSpy/TreeNodes/DerivedTypesTreeNode.cs
+++ b/ILSpy/TreeNodes/DerivedTypesTreeNode.cs
@@ -92,10 +92,9 @@ namespace ICSharpCode.ILSpy.TreeNodes
return typeRef.GetFullTypeName(referenceMetadata) == typeDef.GetFullTypeName(definitionMetadata);
}
- public override object Decompile(Language language, ITextOutput output, DecompilationOptions options)
+ public override void Decompile(Language language, ITextOutput output, DecompilationOptions options)
{
threading.Decompile(language, output, options, EnsureLazyChildren);
- return true;
}
}
}
\ No newline at end of file
diff --git a/ILSpy/TreeNodes/EventTreeNode.cs b/ILSpy/TreeNodes/EventTreeNode.cs
index c1797f794..1aadff896 100644
--- a/ILSpy/TreeNodes/EventTreeNode.cs
+++ b/ILSpy/TreeNodes/EventTreeNode.cs
@@ -67,10 +67,9 @@ namespace ICSharpCode.ILSpy.TreeNodes
return FilterResult.Hidden;
}
- public override object Decompile(Language language, ITextOutput output, DecompilationOptions options)
+ public override void Decompile(Language language, ITextOutput output, DecompilationOptions options)
{
language.DecompileEvent(EventDefinition, output, options);
- return true;
}
public override bool IsPublicAPI {
diff --git a/ILSpy/TreeNodes/FieldTreeNode.cs b/ILSpy/TreeNodes/FieldTreeNode.cs
index 5d3323beb..5d4d2f7b0 100644
--- a/ILSpy/TreeNodes/FieldTreeNode.cs
+++ b/ILSpy/TreeNodes/FieldTreeNode.cs
@@ -68,10 +68,9 @@ namespace ICSharpCode.ILSpy.TreeNodes
return FilterResult.Hidden;
}
- public override object Decompile(Language language, ITextOutput output, DecompilationOptions options)
+ public override void Decompile(Language language, ITextOutput output, DecompilationOptions options)
{
language.DecompileField(FieldDefinition, output, options);
- return true;
}
public override bool IsPublicAPI {
diff --git a/ILSpy/TreeNodes/ILSpyTreeNode.cs b/ILSpy/TreeNodes/ILSpyTreeNode.cs
index 515188374..11fe3b278 100644
--- a/ILSpy/TreeNodes/ILSpyTreeNode.cs
+++ b/ILSpy/TreeNodes/ILSpyTreeNode.cs
@@ -57,7 +57,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
return FilterResult.Hidden;
}
- public abstract object Decompile(Language language, ITextOutput output, DecompilationOptions options);
+ public abstract void Decompile(Language language, ITextOutput output, DecompilationOptions options);
///
/// Used to implement special view logic for some items.
diff --git a/ILSpy/TreeNodes/MethodTreeNode.cs b/ILSpy/TreeNodes/MethodTreeNode.cs
index 89c12ec10..9e4d95e45 100644
--- a/ILSpy/TreeNodes/MethodTreeNode.cs
+++ b/ILSpy/TreeNodes/MethodTreeNode.cs
@@ -83,10 +83,9 @@ namespace ICSharpCode.ILSpy.TreeNodes
}
}
- public override object Decompile(Language language, ITextOutput output, DecompilationOptions options)
+ public override void Decompile(Language language, ITextOutput output, DecompilationOptions options)
{
language.DecompileMethod(MethodDefinition, output, options);
- return true;
}
public override FilterResult Filter(FilterSettings settings)
diff --git a/ILSpy/TreeNodes/ModuleReferenceTreeNode.cs b/ILSpy/TreeNodes/ModuleReferenceTreeNode.cs
index a363c46db..4d51f46af 100644
--- a/ILSpy/TreeNodes/ModuleReferenceTreeNode.cs
+++ b/ILSpy/TreeNodes/ModuleReferenceTreeNode.cs
@@ -72,11 +72,10 @@ namespace ICSharpCode.ILSpy.TreeNodes
}
}
- public override object Decompile(Language language, ITextOutput output, DecompilationOptions options)
+ public override void Decompile(Language language, ITextOutput output, DecompilationOptions options)
{
language.WriteCommentLine(output, moduleName);
language.WriteCommentLine(output, containsMetadata ? "contains metadata" : "contains no metadata");
- return true;
}
}
}
diff --git a/ILSpy/TreeNodes/NamespaceTreeNode.cs b/ILSpy/TreeNodes/NamespaceTreeNode.cs
index 3b9ff4845..d054603dc 100644
--- a/ILSpy/TreeNodes/NamespaceTreeNode.cs
+++ b/ILSpy/TreeNodes/NamespaceTreeNode.cs
@@ -56,10 +56,9 @@ namespace ICSharpCode.ILSpy.TreeNodes
return FilterResult.Recurse;
}
- public override object Decompile(Language language, ITextOutput output, DecompilationOptions options)
+ public override void Decompile(Language language, ITextOutput output, DecompilationOptions options)
{
language.DecompileNamespace(name, this.Children.OfType().Select(t => t.TypeDefinition), output, options);
- return true;
}
}
}
diff --git a/ILSpy/TreeNodes/PropertyTreeNode.cs b/ILSpy/TreeNodes/PropertyTreeNode.cs
index 3267a1e1a..14769ea66 100644
--- a/ILSpy/TreeNodes/PropertyTreeNode.cs
+++ b/ILSpy/TreeNodes/PropertyTreeNode.cs
@@ -74,10 +74,9 @@ namespace ICSharpCode.ILSpy.TreeNodes
return FilterResult.Hidden;
}
- public override object Decompile(Language language, ITextOutput output, DecompilationOptions options)
+ public override void Decompile(Language language, ITextOutput output, DecompilationOptions options)
{
language.DecompileProperty(PropertyDefinition, output, options);
- return true;
}
public override bool IsPublicAPI {
diff --git a/ILSpy/TreeNodes/ReferenceFolderTreeNode.cs b/ILSpy/TreeNodes/ReferenceFolderTreeNode.cs
index 9121e213f..fde4630f1 100644
--- a/ILSpy/TreeNodes/ReferenceFolderTreeNode.cs
+++ b/ILSpy/TreeNodes/ReferenceFolderTreeNode.cs
@@ -62,7 +62,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
this.Children.Add(new ModuleReferenceTreeNode(parentAssembly, r, metadata));
}
- public override object Decompile(Language language, ITextOutput output, DecompilationOptions options)
+ public override void Decompile(Language language, ITextOutput output, DecompilationOptions options)
{
language.WriteCommentLine(output, $"Detected Target-Framework-Id: {parentAssembly.LoadedAssembly.GetTargetFrameworkIdAsync().Result}");
App.Current.Dispatcher.Invoke(DispatcherPriority.Normal, new Action(EnsureLazyChildren));
@@ -86,7 +86,6 @@ namespace ICSharpCode.ILSpy.TreeNodes
output.Unindent();
output.WriteLine();
}
- return true;
}
}
}
diff --git a/ILSpy/TreeNodes/ResourceListTreeNode.cs b/ILSpy/TreeNodes/ResourceListTreeNode.cs
index 79cc1df50..c67c9d4b1 100644
--- a/ILSpy/TreeNodes/ResourceListTreeNode.cs
+++ b/ILSpy/TreeNodes/ResourceListTreeNode.cs
@@ -64,15 +64,13 @@ namespace ICSharpCode.ILSpy.TreeNodes
return FilterResult.Recurse;
}
- public override object Decompile(Language language, ITextOutput output, DecompilationOptions options)
+ public override void Decompile(Language language, ITextOutput output, DecompilationOptions options)
{
App.Current.Dispatcher.Invoke(DispatcherPriority.Normal, new Action(EnsureLazyChildren));
foreach (ILSpyTreeNode child in this.Children) {
child.Decompile(language, output, options);
output.WriteLine();
}
-
- return true;
}
}
}
diff --git a/ILSpy/TreeNodes/ResourceNodes/ImageListResourceEntryNode.cs b/ILSpy/TreeNodes/ResourceNodes/ImageListResourceEntryNode.cs
index 3805db739..fb8b2199f 100644
--- a/ILSpy/TreeNodes/ResourceNodes/ImageListResourceEntryNode.cs
+++ b/ILSpy/TreeNodes/ResourceNodes/ImageListResourceEntryNode.cs
@@ -75,10 +75,9 @@ namespace ICSharpCode.ILSpy.TreeNodes
}
- public override object Decompile(Language language, ITextOutput output, DecompilationOptions options)
+ public override void Decompile(Language language, ITextOutput output, DecompilationOptions options)
{
EnsureLazyChildren();
- return true;
}
}
}
diff --git a/ILSpy/TreeNodes/ResourceNodes/ResourceEntryNode.cs b/ILSpy/TreeNodes/ResourceNodes/ResourceEntryNode.cs
index cf5a3d5ac..ec74ad193 100644
--- a/ILSpy/TreeNodes/ResourceNodes/ResourceEntryNode.cs
+++ b/ILSpy/TreeNodes/ResourceNodes/ResourceEntryNode.cs
@@ -73,10 +73,9 @@ namespace ICSharpCode.ILSpy.TreeNodes
return result;
}
- public override object Decompile(Language language, ITextOutput output, DecompilationOptions options)
+ public override void Decompile(Language language, ITextOutput output, DecompilationOptions options)
{
language.WriteCommentLine(output, string.Format("{0} = {1}", key, data));
- return true;
}
public override bool Save(DecompilerTextView textView)
diff --git a/ILSpy/TreeNodes/ResourceNodes/ResourceTreeNode.cs b/ILSpy/TreeNodes/ResourceNodes/ResourceTreeNode.cs
index c9adaa49c..3433f70d7 100644
--- a/ILSpy/TreeNodes/ResourceNodes/ResourceTreeNode.cs
+++ b/ILSpy/TreeNodes/ResourceNodes/ResourceTreeNode.cs
@@ -67,7 +67,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
return FilterResult.Hidden;
}
- public override object Decompile(Language language, ITextOutput output, DecompilationOptions options)
+ public override void Decompile(Language language, ITextOutput output, DecompilationOptions options)
{
language.WriteCommentLine(output, string.Format("{0} ({1}, {2})", r.Name, r.ResourceType, r.Attributes));
@@ -76,8 +76,6 @@ namespace ICSharpCode.ILSpy.TreeNodes
smartOutput.AddButton(Images.Save, Resources.Save, delegate { Save(MainWindow.Instance.TextView); });
output.WriteLine();
}
-
- return true;
}
public override bool View(DecompilerTextView textView)
diff --git a/ILSpy/TreeNodes/ResourceNodes/ResourcesFileTreeNode.cs b/ILSpy/TreeNodes/ResourceNodes/ResourcesFileTreeNode.cs
index a44edeae4..c1d908481 100644
--- a/ILSpy/TreeNodes/ResourceNodes/ResourcesFileTreeNode.cs
+++ b/ILSpy/TreeNodes/ResourceNodes/ResourcesFileTreeNode.cs
@@ -141,7 +141,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
return true;
}
- public override object Decompile(Language language, ITextOutput output, DecompilationOptions options)
+ public override void Decompile(Language language, ITextOutput output, DecompilationOptions options)
{
EnsureLazyChildren();
base.Decompile(language, output, options);
@@ -168,8 +168,6 @@ namespace ICSharpCode.ILSpy.TreeNodes
}
output.WriteLine();
}
-
- return true;
}
internal class SerializedObjectRepresentation
diff --git a/ILSpy/TreeNodes/ThreadingSupport.cs b/ILSpy/TreeNodes/ThreadingSupport.cs
index 8df078cad..e95787efc 100644
--- a/ILSpy/TreeNodes/ThreadingSupport.cs
+++ b/ILSpy/TreeNodes/ThreadingSupport.cs
@@ -128,9 +128,8 @@ namespace ICSharpCode.ILSpy.TreeNodes
return FilterResult.Match;
}
- public override object Decompile(Language language, ITextOutput output, DecompilationOptions options)
+ public override void Decompile(Language language, ITextOutput output, DecompilationOptions options)
{
- return false;
}
}
@@ -152,9 +151,8 @@ namespace ICSharpCode.ILSpy.TreeNodes
return FilterResult.Match;
}
- public override object Decompile(Language language, ITextOutput output, DecompilationOptions options)
+ public override void Decompile(Language language, ITextOutput output, DecompilationOptions options)
{
- return false;
}
}
diff --git a/ILSpy/TreeNodes/TypeTreeNode.cs b/ILSpy/TreeNodes/TypeTreeNode.cs
index 4464a3521..3ef91c411 100644
--- a/ILSpy/TreeNodes/TypeTreeNode.cs
+++ b/ILSpy/TreeNodes/TypeTreeNode.cs
@@ -103,10 +103,9 @@ namespace ICSharpCode.ILSpy.TreeNodes
public override bool CanExpandRecursively => true;
- public override object Decompile(Language language, ITextOutput output, DecompilationOptions options)
+ public override void Decompile(Language language, ITextOutput output, DecompilationOptions options)
{
language.DecompileType(TypeDefinition, output, options);
- return true;
}
public override object Icon => GetIcon(TypeDefinition);