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.