diff --git a/ILSpy.sln b/ILSpy.sln index a4ff171cd..40c5aca08 100644 --- a/ILSpy.sln +++ b/ILSpy.sln @@ -1,7 +1,12 @@  Microsoft Visual Studio Solution File, Format Version 11.00 # Visual Studio 2010 -# SharpDevelop 4.0.1.7126 +# SharpDevelop 4.0.1.7146 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "doc", "doc", "{F45DB999-7E72-4000-B5AD-3A7B485A0896}" + ProjectSection(SolutionItems) = postProject + doc\Command Line.txt = doc\Command Line.txt + EndProjectSection +EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ILSpy", "ILSpy\ILSpy.csproj", "{1E85EFF9-E370-4683-83E4-8A3D063FF791}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.TreeView", "SharpTreeView\ICSharpCode.TreeView.csproj", "{DDE2A481-8271-4EAC-A330-8FA6A38D13D1}" @@ -16,10 +21,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.NRefactory", "N EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.Decompiler.Tests", "ICSharpCode.Decompiler\Tests\ICSharpCode.Decompiler.Tests.csproj", "{FEC0DA52-C4A6-4710-BE36-B484A20C5E22}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "doc", "doc", "{F45DB999-7E72-4000-B5AD-3A7B485A0896}" - ProjectSection(SolutionItems) = postProject - doc\Command Line.txt = doc\Command Line.txt - EndProjectSection +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestPlugin", "TestPlugin\TestPlugin.csproj", "{F32EBCC8-0E53-4421-867E-05B3D6E10C70}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -85,6 +87,14 @@ Global {FEC0DA52-C4A6-4710-BE36-B484A20C5E22}.Release|Any CPU.Build.0 = Release|x86 {FEC0DA52-C4A6-4710-BE36-B484A20C5E22}.Release|x86.ActiveCfg = Release|x86 {FEC0DA52-C4A6-4710-BE36-B484A20C5E22}.Release|x86.Build.0 = Release|x86 + {F32EBCC8-0E53-4421-867E-05B3D6E10C70}.Debug|Any CPU.Build.0 = Debug|x86 + {F32EBCC8-0E53-4421-867E-05B3D6E10C70}.Debug|Any CPU.ActiveCfg = Debug|x86 + {F32EBCC8-0E53-4421-867E-05B3D6E10C70}.Debug|x86.Build.0 = Debug|x86 + {F32EBCC8-0E53-4421-867E-05B3D6E10C70}.Debug|x86.ActiveCfg = Debug|x86 + {F32EBCC8-0E53-4421-867E-05B3D6E10C70}.Release|Any CPU.Build.0 = Release|x86 + {F32EBCC8-0E53-4421-867E-05B3D6E10C70}.Release|Any CPU.ActiveCfg = Release|x86 + {F32EBCC8-0E53-4421-867E-05B3D6E10C70}.Release|x86.Build.0 = Release|x86 + {F32EBCC8-0E53-4421-867E-05B3D6E10C70}.Release|x86.ActiveCfg = Release|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/ILSpy/AssemblyList.cs b/ILSpy/AssemblyList.cs index 336d7c4f3..7229a6503 100644 --- a/ILSpy/AssemblyList.cs +++ b/ILSpy/AssemblyList.cs @@ -130,8 +130,18 @@ namespace ICSharpCode.ILSpy } var newAsm = new LoadedAssembly(this, file); - this.assemblies.Add(newAsm); + lock (assemblies) { + this.assemblies.Add(newAsm); + } return newAsm; } + + public void Unload(LoadedAssembly assembly) + { + App.Current.Dispatcher.VerifyAccess(); + lock (assemblies) { + assemblies.Remove(assembly); + } + } } } diff --git a/ILSpy/ILSpy.csproj b/ILSpy/ILSpy.csproj index 7238a762d..09515d5b3 100644 --- a/ILSpy/ILSpy.csproj +++ b/ILSpy/ILSpy.csproj @@ -17,6 +17,7 @@ false Images\ILSpy.ico False + /separate x86 diff --git a/ILSpy/Images/Images.cs b/ILSpy/Images/Images.cs index dbaf2e2b9..ec526d543 100644 --- a/ILSpy/Images/Images.cs +++ b/ILSpy/Images/Images.cs @@ -78,10 +78,13 @@ namespace ICSharpCode.ILSpy public static BitmapImage LoadImage(object part, string icon) { Uri uri; - if (part.GetType().Assembly == typeof(Images).Assembly) + var assembly = part.GetType().Assembly; + if (assembly == typeof(Images).Assembly) { uri = new Uri("pack://application:,,,/" + icon); - else - throw new NotImplementedException(); + } else { + var name = assembly.GetName(); + uri = new Uri("pack://application:,,,/" + name.Name + ";v" + name.Version + ";component/" + icon); + } BitmapImage image = new BitmapImage(uri); image.Freeze(); return image; diff --git a/ILSpy/MainWindow.xaml.cs b/ILSpy/MainWindow.xaml.cs index 60ee6d04a..a4fdd0791 100644 --- a/ILSpy/MainWindow.xaml.cs +++ b/ILSpy/MainWindow.xaml.cs @@ -209,6 +209,10 @@ namespace ICSharpCode.ILSpy } #endregion + public AssemblyList CurrentAssemblyList { + get { return assemblyList; } + } + List commandLineLoadedAssemblies = new List(); bool HandleCommandLineArguments(CommandLineArguments args) @@ -371,10 +375,6 @@ namespace ICSharpCode.ILSpy assemblyListTreeNode.FilterSettings = sessionSettings.FilterSettings.Clone(); } - internal AssemblyList AssemblyList { - get { return assemblyList; } - } - internal AssemblyListTreeNode AssemblyListTreeNode { get { return assemblyListTreeNode; } } diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedFieldAccessNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedFieldAccessNode.cs index 200f8e693..59d8b47c2 100644 --- a/ILSpy/TreeNodes/Analyzer/AnalyzedFieldAccessNode.cs +++ b/ILSpy/TreeNodes/Analyzer/AnalyzedFieldAccessNode.cs @@ -54,7 +54,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer IEnumerable FetchChildren(CancellationToken ct) { - return FindReferences(MainWindow.Instance.AssemblyList.GetAssemblies(), ct); + return FindReferences(MainWindow.Instance.CurrentAssemblyList.GetAssemblies(), ct); } IEnumerable FindReferences(IEnumerable assemblies, CancellationToken ct) diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedMethodUsedByTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedMethodUsedByTreeNode.cs index 4c7900c12..e80c77b68 100644 --- a/ILSpy/TreeNodes/Analyzer/AnalyzedMethodUsedByTreeNode.cs +++ b/ILSpy/TreeNodes/Analyzer/AnalyzedMethodUsedByTreeNode.cs @@ -67,7 +67,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer IEnumerable FetchChildren(CancellationToken ct) { - return FindReferences(MainWindow.Instance.AssemblyList.GetAssemblies(), ct); + return FindReferences(MainWindow.Instance.CurrentAssemblyList.GetAssemblies(), ct); } IEnumerable FindReferences(IEnumerable assemblies, CancellationToken ct) diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedPropertyOverridesTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedPropertyOverridesTreeNode.cs index cb7a810a8..a4d028dc1 100644 --- a/ILSpy/TreeNodes/Analyzer/AnalyzedPropertyOverridesTreeNode.cs +++ b/ILSpy/TreeNodes/Analyzer/AnalyzedPropertyOverridesTreeNode.cs @@ -51,7 +51,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer IEnumerable FetchChildren(CancellationToken ct) { - return FindReferences(MainWindow.Instance.AssemblyList.GetAssemblies(), ct); + return FindReferences(MainWindow.Instance.CurrentAssemblyList.GetAssemblies(), ct); } IEnumerable FindReferences(IEnumerable assemblies, CancellationToken ct) diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzerMethodOverridesTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzerMethodOverridesTreeNode.cs index 753f02b9e..4244c595d 100644 --- a/ILSpy/TreeNodes/Analyzer/AnalyzerMethodOverridesTreeNode.cs +++ b/ILSpy/TreeNodes/Analyzer/AnalyzerMethodOverridesTreeNode.cs @@ -55,7 +55,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer IEnumerable FetchChildren(CancellationToken ct) { - return FindReferences(MainWindow.Instance.AssemblyList.GetAssemblies(), ct); + return FindReferences(MainWindow.Instance.CurrentAssemblyList.GetAssemblies(), ct); } IEnumerable FindReferences(IEnumerable assemblies, CancellationToken ct) diff --git a/ILSpy/TreeNodes/AssemblyTreeNode.cs b/ILSpy/TreeNodes/AssemblyTreeNode.cs index 99a56e2ff..2d3aad07e 100644 --- a/ILSpy/TreeNodes/AssemblyTreeNode.cs +++ b/ILSpy/TreeNodes/AssemblyTreeNode.cs @@ -161,9 +161,7 @@ namespace ICSharpCode.ILSpy.TreeNodes public override void DeleteCore() { - lock (assembly.AssemblyList.assemblies) { - assembly.AssemblyList.assemblies.Remove(assembly); - } + assembly.AssemblyList.Unload(assembly); } internal const string DataFormat = "ILSpyAssemblies"; diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/AstNode.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/AstNode.cs index ab8377685..f0bd67d10 100644 --- a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/AstNode.cs +++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/AstNode.cs @@ -383,7 +383,7 @@ namespace ICSharpCode.NRefactory.CSharp /// /// Clones the whole subtree starting at this AST node. /// - /// Annotations are copied over to the new nodes; and any annotations implementating ICloneable will be cloned. + /// Annotations are copied over to the new nodes; and any annotations implementing ICloneable will be cloned. public AstNode Clone() { AstNode copy = (AstNode)MemberwiseClone(); @@ -401,9 +401,9 @@ namespace ICSharpCode.NRefactory.CSharp } // Finally, clone the annotation, if necessary - ICloneable annotations = copy.annotations as ICloneable; // read from copy (for thread-safety) - if (annotations != null) - copy.annotations = annotations.Clone(); + ICloneable copiedAnnotations = copy.annotations as ICloneable; // read from copy (for thread-safety) + if (copiedAnnotations != null) + copy.annotations = copiedAnnotations.Clone(); return copy; } diff --git a/TestPlugin/Clear.png b/TestPlugin/Clear.png new file mode 100644 index 000000000..47e7d601a Binary files /dev/null and b/TestPlugin/Clear.png differ diff --git a/TestPlugin/CustomLanguage.cs b/TestPlugin/CustomLanguage.cs new file mode 100644 index 000000000..bdc90ee08 --- /dev/null +++ b/TestPlugin/CustomLanguage.cs @@ -0,0 +1,60 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under MIT X11 license (for details please see \doc\license.txt) + +using System; +using System.ComponentModel.Composition; +using System.Linq; +using System.Windows.Controls; +using ICSharpCode.Decompiler; +using ICSharpCode.Decompiler.Ast; +using ICSharpCode.ILSpy; +using ICSharpCode.NRefactory.CSharp; +using Mono.Cecil; + +namespace TestPlugin +{ + /// + /// Adds a new language to the decompiler. + /// + [Export(typeof(Language))] + public class CustomLanguage : Language + { + public override string Name { + get { + return "Custom"; + } + } + + public override string FileExtension { + get { + // used in 'Save As' dialog + return ".txt"; + } + } + + // There are several methods available to override; in this sample, we deal with methods only + + public override void DecompileMethod(MethodDefinition method, ITextOutput output, DecompilationOptions options) + { + if (method.Body != null) { + output.WriteLine("Size of method: {0} bytes", method.Body.CodeSize); + + ISmartTextOutput smartOutput = output as ISmartTextOutput; + if (smartOutput != null) { + // when writing to the text view (but not when writing to a file), we can even add UI elements such as buttons: + smartOutput.AddButton(null, "Click me!", (sender, e) => (sender as Button).Content = "I was clicked!"); + smartOutput.WriteLine(); + } + + // ICSharpCode.Decompiler.Ast.AstBuilder can be used to decompile to C# + AstBuilder b = new AstBuilder(new DecompilerContext(method.Module) { + Settings = options.DecompilerSettings, + CurrentType = method.DeclaringType + }); + b.AddMethod(method); + b.RunTransformations(); + output.WriteLine("Decompiled AST has {0} nodes", b.CompilationUnit.DescendantsAndSelf.Count()); + } + } + } +} diff --git a/TestPlugin/MainMenuCommand.cs b/TestPlugin/MainMenuCommand.cs new file mode 100644 index 000000000..bbda41ace --- /dev/null +++ b/TestPlugin/MainMenuCommand.cs @@ -0,0 +1,29 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under MIT X11 license (for details please see \doc\license.txt) + +using System; +using ICSharpCode.ILSpy; + +namespace TestPlugin +{ + // Menu: menu into which the item is added + // MenuIcon: optional, icon to use for the menu item. Must be embedded as "Resource" (WPF-style resource) in the same assembly as the command type. + // Header: text on the menu item + // MenuCategory: optional, used for grouping related menu items together. A separator is added between different groups. + // MenuOrder: controls the order in which the items appear (items are sorted by this value) + [ExportMainMenuCommand(Menu = "_File", MenuIcon = "Clear.png", Header = "_Clear List", MenuCategory = "Open", MenuOrder = 1.5)] + // ToolTip: the tool tip + // ToolbarIcon: The icon. Must be embedded as "Resource" (WPF-style resource) in the same assembly as the command type. + // ToolbarCategory: optional, used for grouping related toolbar items together. A separator is added between different groups. + // ToolbarOrder: controls the order in which the items appear (items are sorted by this value) + [ExportToolbarCommand(ToolTip = "Clears the current assembly list", ToolbarIcon = "Clear.png", ToolbarCategory = "Open", ToolbarOrder = 1.5)] + public class UnloadAllAssembliesCommand : SimpleCommand + { + public override void Execute(object parameter) + { + foreach (var loadedAssembly in MainWindow.Instance.CurrentAssemblyList.GetAssemblies()) { + loadedAssembly.AssemblyList.Unload(loadedAssembly); + } + } + } +} diff --git a/TestPlugin/Properties/AssemblyInfo.cs b/TestPlugin/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..48726c57e --- /dev/null +++ b/TestPlugin/Properties/AssemblyInfo.cs @@ -0,0 +1,31 @@ +#region Using directives + +using System; +using System.Reflection; +using System.Runtime.InteropServices; + +#endregion + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("TestPlugin")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("TestPlugin")] +[assembly: AssemblyCopyright("Copyright 2011")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// This sets the default COM visibility of types in the assembly to invisible. +// If you need to expose a type to COM, use [ComVisible(true)] on that type. +[assembly: ComVisible(false)] + +// The assembly version has following format : +// +// Major.Minor.Build.Revision +// +// You can specify all the values or you can use the default the Revision and +// Build Numbers by using the '*' as shown below: +[assembly: AssemblyVersion("1.0.*")] diff --git a/TestPlugin/Readme.txt b/TestPlugin/Readme.txt new file mode 100644 index 000000000..f2d42a0a4 --- /dev/null +++ b/TestPlugin/Readme.txt @@ -0,0 +1,25 @@ +ILSpy uses MEF (Managed Extensibility Framework) for plugins. +Plugins must be placed in the same directory as ILSpy.exe, and must be called "*.Plugin.dll". + +To write a plugin, you need to add a reference to ILSpy.exe and to System.ComponentModel.Composition. +Depending on what your plugin is doing, you might also need references to the other libraries shipping with ILSpy. + +Plugins work by exporting types for certain extension points. +Here is a list of extension points: + +Adding another language: + + [Export(typeof(Language))] + public class CustomLanguage : Language + + This adds an additional language to the combobox in the toolbar. + The language has to implement its own decompiler (all the way from IL), but it can also re-use + the ICSharpCode.Decompiler library to decompile to C#, and then translate the C# code to the target language. + +--- + +Adding an entry to the main menu: + + [ExportMainMenuCommand(Menu = "_File", Header = "_Clear List", MenuCategory = "Open", MenuOrder = 1.5)] + public class UnloadAllAssembliesCommand : SimpleCommand + diff --git a/TestPlugin/TestPlugin.csproj b/TestPlugin/TestPlugin.csproj new file mode 100644 index 000000000..4299e5c4b --- /dev/null +++ b/TestPlugin/TestPlugin.csproj @@ -0,0 +1,98 @@ + + + + {F32EBCC8-0E53-4421-867E-05B3D6E10C70} + Debug + x86 + Library + TestPlugin + Test.Plugin + v4.0 + Properties + False + False + 4 + false + /separate + + + x86 + False + Auto + 4194304 + 4096 + + + bin\Debug\ + true + Full + False + True + DEBUG;TRACE + Program + bin\Debug\ILSpy.exe + + + bin\Release\ + False + None + True + False + TRACE + Program + bin\Release\ILSpy.exe + + + + 3.0 + + + 3.0 + + + + 4.0 + + + 3.5 + + + 4.0 + + + + 3.5 + + + 3.0 + + + + + + + + + + + + + + {984CC812-9470-4A13-AFF9-CC44068D666C} + ICSharpCode.Decompiler + + + {1E85EFF9-E370-4683-83E4-8A3D063FF791} + ILSpy + + + {D68133BD-1E63-496E-9EDE-4FBDBF77B486} + Mono.Cecil + + + {3B2A5653-EC97-4001-BB9B-D90F1AF2C371} + ICSharpCode.NRefactory + + + + \ No newline at end of file diff --git a/doc/Command Line.txt b/doc/Command Line.txt index 0aef7a2d6..c0486933b 100644 --- a/doc/Command Line.txt +++ b/doc/Command Line.txt @@ -10,7 +10,7 @@ Available options: /separate Start up a separate ILSpy instance even if it is already running. - /noActivate Do not activate the existing ILSpy instance. This option has no effec + /noActivate Do not activate the existing ILSpy instance. This option has no effect if a new ILSpy instance is being started. /list:listname Specifies the name of the assembly list that is loaded initially.