From 0d390d604fd9b54d5ce2748302bd30696abc6122 Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Sat, 23 May 2020 19:21:48 +0200 Subject: [PATCH] Fix #2013: Add option to extract self-contained executables (PublishSingleFile). --- ILSpy.AddIn/ILSpy.AddIn.csproj | 12 +++-- ILSpy/ILSpy.csproj | 2 + ILSpy/MainWindow.xaml.cs | 75 ++++++++++++++++++++++---- ILSpy/Properties/Resources.Designer.cs | 15 ++++++ ILSpy/Properties/Resources.resx | 9 ++++ 5 files changed, 99 insertions(+), 14 deletions(-) diff --git a/ILSpy.AddIn/ILSpy.AddIn.csproj b/ILSpy.AddIn/ILSpy.AddIn.csproj index 5a96857ac..1d1a3cea9 100644 --- a/ILSpy.AddIn/ILSpy.AddIn.csproj +++ b/ILSpy.AddIn/ILSpy.AddIn.csproj @@ -117,12 +117,14 @@ - + - - - - + + + + + + diff --git a/ILSpy/ILSpy.csproj b/ILSpy/ILSpy.csproj index 201719e62..a371180ea 100644 --- a/ILSpy/ILSpy.csproj +++ b/ILSpy/ILSpy.csproj @@ -56,6 +56,8 @@ + + diff --git a/ILSpy/MainWindow.xaml.cs b/ILSpy/MainWindow.xaml.cs index ef311f68a..e48569701 100644 --- a/ILSpy/MainWindow.xaml.cs +++ b/ILSpy/MainWindow.xaml.cs @@ -35,6 +35,7 @@ using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Threading; + using ICSharpCode.Decompiler; using ICSharpCode.Decompiler.Documentation; using ICSharpCode.Decompiler.Metadata; @@ -46,7 +47,13 @@ using ICSharpCode.ILSpy.TextView; using ICSharpCode.ILSpy.TreeNodes; using ICSharpCode.ILSpy.ViewModels; using ICSharpCode.TreeView; + +using Microsoft.NET.HostModel.AppHost; +using Microsoft.NET.HostModel.Bundle; using Microsoft.Win32; + +using Ookii.Dialogs.Wpf; + using OSVersionHelper; using Xceed.Wpf.AvalonDock.Layout.Serialization; @@ -994,15 +1001,55 @@ namespace ICSharpCode.ILSpy } break; default: - var asm = assemblyList.OpenAssembly(file); - if (asm != null) { - if (loadedAssemblies != null) - loadedAssemblies.Add(asm); - else { - var node = assemblyListTreeNode.FindAssemblyNode(asm); - if (node != null && focusNode) { - AssemblyTreeView.SelectedItems.Add(node); - lastNode = node; + if (IsAppBundle(file, out var headerOffset)) { + if (MessageBox.Show(this, Properties.Resources.OpenSelfContainedExecutableMessage, "ILSpy", MessageBoxButton.YesNo) == MessageBoxResult.No) + break; + var dialog = new VistaFolderBrowserDialog(); + if (dialog.ShowDialog() != true) + break; + DockWorkspace.Instance.RunWithCancellation(ct => Task.Factory.StartNew(() => { + var output = new AvalonEditTextOutput { Title = "Extracting " + file }; + Stopwatch w = Stopwatch.StartNew(); + output.WriteLine($"Extracting {file} to {dialog.SelectedPath}..."); + var extractor = new Extractor(file, dialog.SelectedPath); + extractor.ExtractFiles(); + output.WriteLine($"Done in {w.Elapsed}."); + return output; + }, ct)).Then(output => { + DockWorkspace.Instance.ShowText(output); + + OpenFileDialog dlg = new OpenFileDialog(); + dlg.Filter = ".NET assemblies|*.dll;*.exe;*.winmd"; + dlg.Multiselect = true; + dlg.InitialDirectory = dialog.SelectedPath; + if (dlg.ShowDialog() == true) { + foreach (var item in dlg.FileNames) { + var asm = assemblyList.OpenAssembly(item); + if (asm != null) { + if (loadedAssemblies != null) + loadedAssemblies.Add(asm); + else { + var node = assemblyListTreeNode.FindAssemblyNode(asm); + if (node != null && focusNode) { + AssemblyTreeView.SelectedItems.Add(node); + lastNode = node; + } + } + } + } + } + }).HandleExceptions(); + } else { + var asm = assemblyList.OpenAssembly(file); + if (asm != null) { + if (loadedAssemblies != null) + loadedAssemblies.Add(asm); + else { + var node = assemblyListTreeNode.FindAssemblyNode(asm); + if (node != null && focusNode) { + AssemblyTreeView.SelectedItems.Add(node); + lastNode = node; + } } } } @@ -1012,6 +1059,16 @@ namespace ICSharpCode.ILSpy if (lastNode != null && focusNode) AssemblyTreeView.FocusNode(lastNode); } + + bool IsAppBundle(string filename, out long bundleHeaderOffset) + { + try { + return HostWriter.IsBundle(filename, out bundleHeaderOffset); + } catch (Exception) { + bundleHeaderOffset = -1; + return false; + } + } } void RefreshCommandExecuted(object sender, ExecutedRoutedEventArgs e) diff --git a/ILSpy/Properties/Resources.Designer.cs b/ILSpy/Properties/Resources.Designer.cs index 10b87ca5c..51507cb90 100644 --- a/ILSpy/Properties/Resources.Designer.cs +++ b/ILSpy/Properties/Resources.Designer.cs @@ -1605,6 +1605,21 @@ namespace ICSharpCode.ILSpy.Properties { } } + /// + /// Looks up a localized string similar to You are trying to open a single-file executable (app bundle). In order to work with this type of program, ILSpy will + /// + ///(i) show you a dialog to select a folder to extract the bundle to + ///(ii) extract the assemblies (might take a few seconds) + ///(iii) show you a dialog to select one or more of those extracted assemblies to decompile + /// + ///Do you want to proceed?. + /// + public static string OpenSelfContainedExecutableMessage { + get { + return ResourceManager.GetString("OpenSelfContainedExecutableMessage", resourceCulture); + } + } + /// /// Looks up a localized string similar to Options. /// diff --git a/ILSpy/Properties/Resources.resx b/ILSpy/Properties/Resources.resx index d89524790..b8708bf57 100644 --- a/ILSpy/Properties/Resources.resx +++ b/ILSpy/Properties/Resources.resx @@ -867,4 +867,13 @@ Do you want to continue? Culture + + You are trying to open a single-file executable (app bundle). In order to work with this type of program, ILSpy will + +(i) show you a dialog to select a folder to extract the bundle to +(ii) extract the assemblies (might take a few seconds) +(iii) show you a dialog to select one or more of those extracted assemblies to decompile + +Do you want to proceed? + \ No newline at end of file