diff --git a/ILSpy/App.xaml.cs b/ILSpy/App.xaml.cs
index 079b6d00f..39af423cb 100644
--- a/ILSpy/App.xaml.cs
+++ b/ILSpy/App.xaml.cs
@@ -18,9 +18,11 @@
using System;
using System.Diagnostics;
+using System.Threading;
using System.Windows;
using System.Windows.Documents;
using System.Windows.Navigation;
+using System.Windows.Threading;
namespace ICSharpCode.ILSpy
{
@@ -33,11 +35,33 @@ namespace ICSharpCode.ILSpy
{
InitializeComponent();
+ if (!Debugger.IsAttached) {
+ AppDomain.CurrentDomain.UnhandledException += ShowErrorBox;
+ Dispatcher.CurrentDispatcher.UnhandledException += Dispatcher_UnhandledException;
+ }
+
EventManager.RegisterClassHandler(typeof(Window),
Hyperlink.RequestNavigateEvent,
new RequestNavigateEventHandler(Window_RequestNavigate));
}
+
+ static void Dispatcher_UnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
+ {
+ Debug.WriteLine(e.Exception.ToString());
+ MessageBox.Show(e.Exception.ToString(), "Sorry, we crashed");
+ e.Handled = true;
+ }
+
+ static void ShowErrorBox(object sender, UnhandledExceptionEventArgs e)
+ {
+ Exception ex = e.ExceptionObject as Exception;
+ if (ex != null) {
+ Debug.WriteLine(ex.ToString());
+ MessageBox.Show(ex.ToString(), "Sorry, we crashed");
+ }
+ }
+
void Window_RequestNavigate(object sender, RequestNavigateEventArgs e)
{
Process.Start(e.Uri.ToString());
diff --git a/ILSpy/FilterSettings.cs b/ILSpy/FilterSettings.cs
index df6213104..5283c2d46 100644
--- a/ILSpy/FilterSettings.cs
+++ b/ILSpy/FilterSettings.cs
@@ -18,6 +18,8 @@
using System;
using System.ComponentModel;
+using System.Linq;
+using System.Xml.Linq;
namespace ICSharpCode.ILSpy
{
@@ -31,6 +33,21 @@ namespace ICSharpCode.ILSpy
///
public class FilterSettings : INotifyPropertyChanged
{
+ public FilterSettings(XElement element)
+ {
+ this.ShowInternalApi = (bool?)element.Element("ShowInternalAPI") ?? true;
+ this.Language = Languages.GetLanguage((string)element.Element("Language"));
+ }
+
+ public XElement SaveAsXml()
+ {
+ return new XElement(
+ "FilterSettings",
+ new XElement("ShowInternalAPI", this.ShowInternalApi),
+ new XElement("Language", this.Language.Name)
+ );
+ }
+
string searchTerm;
public string SearchTerm {
@@ -50,7 +67,7 @@ namespace ICSharpCode.ILSpy
return text.IndexOf(searchTerm, StringComparison.OrdinalIgnoreCase) >= 0;
}
- bool showInternalApi = true;
+ bool showInternalApi;
public bool ShowInternalApi {
get { return showInternalApi; }
@@ -62,7 +79,7 @@ namespace ICSharpCode.ILSpy
}
}
- Language language = Languages.AllLanguages[0];
+ Language language;
public Language Language {
get { return language; }
diff --git a/ILSpy/ILSpy.csproj b/ILSpy/ILSpy.csproj
index d49ac75a4..0aaf7e826 100644
--- a/ILSpy/ILSpy.csproj
+++ b/ILSpy/ILSpy.csproj
@@ -89,6 +89,7 @@
+
@@ -103,6 +104,7 @@
Code
MainWindow.xaml
+
diff --git a/ILSpy/ILSpySettings.cs b/ILSpy/ILSpySettings.cs
new file mode 100644
index 000000000..10b46c836
--- /dev/null
+++ b/ILSpy/ILSpySettings.cs
@@ -0,0 +1,101 @@
+// Copyright (c) 2011 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;
+using System.Linq;
+using System.Threading;
+using System.Xml;
+using System.Xml.Linq;
+
+namespace ICSharpCode.ILSpy
+{
+ ///
+ /// Manages IL Spy settings.
+ ///
+ public static class ILSpySettings
+ {
+ public static XElement LoadSettings(string section)
+ {
+ using (new MutexProtector(ConfigFileMutex)) {
+ try {
+ XDocument doc = XDocument.Load(GetConfigFile());
+ return doc.Root.Element(section) ?? new XElement(section);
+ } catch (IOException) {
+ return new XElement(section);
+ } catch (XmlException) {
+ return new XElement(section);
+ }
+ }
+ }
+
+ public static void SaveSettings(XElement section)
+ {
+ using (new MutexProtector(ConfigFileMutex)) {
+ string config = GetConfigFile();
+ XDocument doc;
+ try {
+ doc = XDocument.Load(config);
+ } catch (IOException) {
+ // ensure the directory exists
+ Directory.CreateDirectory(Path.GetDirectoryName(config));
+ doc = new XDocument(new XElement("ILSpy"));
+ } catch (XmlException) {
+ doc = new XDocument(new XElement("ILSpy"));
+ }
+ doc.Root.SetAttributeValue("version", RevisionClass.Major + "." + RevisionClass.Minor + "." + RevisionClass.Build + "." + RevisionClass.Revision);
+ XElement existingElement = doc.Root.Element(section.Name);
+ if (existingElement != null)
+ existingElement.ReplaceWith(section);
+ else
+ doc.Root.Add(section);
+ doc.Save(config);
+ }
+ }
+
+ public static string GetConfigFile()
+ {
+ return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "ICSharpCode\\ILSpy.xml");
+ }
+
+ const string ConfigFileMutex = "01A91708-49D1-410D-B8EB-4DE2662B3971";
+
+ sealed class MutexProtector : IDisposable
+ {
+ Mutex mutex;
+
+ public MutexProtector(string name)
+ {
+ bool createdNew;
+ this.mutex = new Mutex(true, name, out createdNew);
+ if (!createdNew) {
+ try {
+ mutex.WaitOne();
+ } catch (AbandonedMutexException) {
+ }
+ }
+ }
+
+ public void Dispose()
+ {
+ mutex.ReleaseMutex();
+ mutex.Dispose();
+ }
+ }
+ }
+}
diff --git a/ILSpy/Language.cs b/ILSpy/Language.cs
index 3f8876d62..92ac30b07 100644
--- a/ILSpy/Language.cs
+++ b/ILSpy/Language.cs
@@ -18,6 +18,7 @@
using System;
using System.Collections.Generic;
+using System.Linq;
using ICSharpCode.Decompiler;
using Mono.Cecil;
@@ -80,5 +81,10 @@ namespace ICSharpCode.ILSpy
new ILLanguage(false),
new ILLanguage(true)
};
+
+ public static Language GetLanguage(string name)
+ {
+ return AllLanguages.FirstOrDefault(l => l.Name == name) ?? AllLanguages.First();
+ }
}
}
diff --git a/ILSpy/MainWindow.xaml b/ILSpy/MainWindow.xaml
index 1a63c6319..79b02d79c 100644
--- a/ILSpy/MainWindow.xaml
+++ b/ILSpy/MainWindow.xaml
@@ -3,8 +3,6 @@
x:Class="ICSharpCode.ILSpy.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:tv="clr-namespace:ICSharpCode.TreeView;assembly=ICSharpCode.TreeView"
xmlns:local="clr-namespace:ICSharpCode.ILSpy" xmlns:textView="clr-namespace:ICSharpCode.ILSpy.TextView"
Title="ILSpy"
- Width="790"
- Height="500"
MinWidth="250"
MinHeight="200"
UseLayoutRounding="True"
diff --git a/ILSpy/MainWindow.xaml.cs b/ILSpy/MainWindow.xaml.cs
index 2f6750a79..49501bcf8 100644
--- a/ILSpy/MainWindow.xaml.cs
+++ b/ILSpy/MainWindow.xaml.cs
@@ -17,6 +17,7 @@
// DEALINGS IN THE SOFTWARE.
using System;
+using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
@@ -39,7 +40,7 @@ namespace ICSharpCode.ILSpy
{
AssemblyList assemblyList = new AssemblyList();
AssemblyListTreeNode assemblyListTreeNode;
- FilterSettings filterSettings = new FilterSettings();
+ SessionSettings settings = new SessionSettings();
static readonly System.Reflection.Assembly[] initialAssemblies = {
typeof(object).Assembly,
@@ -58,13 +59,20 @@ namespace ICSharpCode.ILSpy
public MainWindow()
{
- this.DataContext = filterSettings;
+ this.DataContext = settings.FilterSettings;
+ this.Left = settings.WindowBounds.Left;
+ this.Top = settings.WindowBounds.Top;
+ this.Width = settings.WindowBounds.Width;
+ this.Height = settings.WindowBounds.Height;
+ // TODO: validate bounds (maybe a screen was removed...)
+ this.WindowState = settings.WindowState;
+
InitializeComponent();
decompilerTextView.mainWindow = this;
assemblyListTreeNode = new AssemblyListTreeNode(assemblyList);
- assemblyListTreeNode.FilterSettings = filterSettings.Clone();
- filterSettings.PropertyChanged += new PropertyChangedEventHandler(filterSettings_PropertyChanged);
+ assemblyListTreeNode.FilterSettings = settings.FilterSettings.Clone();
+ settings.FilterSettings.PropertyChanged += new PropertyChangedEventHandler(filterSettings_PropertyChanged);
treeView.Root = assemblyListTreeNode;
assemblyListTreeNode.Select = SelectNode;
@@ -75,6 +83,8 @@ namespace ICSharpCode.ILSpy
assemblyList.OpenAssembly(args[i]);
}
+ SelectNode(FindNodeByPath(settings.ActiveTreeViewPath));
+
#if DEBUG
AddDebugItemsToToolbar();
#endif
@@ -85,7 +95,7 @@ namespace ICSharpCode.ILSpy
// filterSettings is mutable; but the ILSpyTreeNode filtering assumes that filter settings are immutable.
// Thus, the main window will use one mutable instance (for data-binding), and assign a new clone to the ILSpyTreeNodes whenever the main
// mutable instance changes.
- assemblyListTreeNode.FilterSettings = filterSettings.Clone();
+ assemblyListTreeNode.FilterSettings = settings.FilterSettings.Clone();
if (e.PropertyName == "Language") {
TreeView_SelectionChanged(null, null);
}
@@ -103,6 +113,33 @@ namespace ICSharpCode.ILSpy
}
}
+ SharpTreeNode FindNodeByPath(string[] path)
+ {
+ if (path == null)
+ return null;
+ SharpTreeNode node = treeView.Root;
+ foreach (var element in path) {
+ if (node == null)
+ break;
+ node.EnsureLazyChildren();
+ node = node.Children.FirstOrDefault(c => c.ToString() == element);
+ }
+ return node;
+ }
+
+ string[] GetPathForNode(SharpTreeNode node)
+ {
+ if (node == null)
+ return null;
+ List path = new List();
+ while (node.Parent != null) {
+ path.Add(node.ToString());
+ node = node.Parent;
+ }
+ path.Reverse();
+ return path.ToArray();
+ }
+
#region Debugging CFG
#if DEBUG
void AddDebugItemsToToolbar()
@@ -213,7 +250,23 @@ namespace ICSharpCode.ILSpy
void TreeView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
- decompilerTextView.Decompile(filterSettings.Language, treeView.SelectedItems.OfType());
+ decompilerTextView.Decompile(settings.FilterSettings.Language, treeView.SelectedItems.OfType());
+ }
+
+ protected override void OnStateChanged(EventArgs e)
+ {
+ base.OnStateChanged(e);
+ // store window state in settings only if it's not minimized
+ if (this.WindowState != System.Windows.WindowState.Minimized)
+ settings.WindowState = this.WindowState;
+ }
+
+ protected override void OnClosing(CancelEventArgs e)
+ {
+ base.OnClosing(e);
+ settings.ActiveTreeViewPath = GetPathForNode(treeView.SelectedItem as SharpTreeNode);
+ settings.WindowBounds = this.RestoreBounds;
+ settings.Save();
}
}
}
\ No newline at end of file
diff --git a/ILSpy/SessionSettings.cs b/ILSpy/SessionSettings.cs
new file mode 100644
index 000000000..47c8e681e
--- /dev/null
+++ b/ILSpy/SessionSettings.cs
@@ -0,0 +1,73 @@
+// 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;
+using System.Linq;
+using System.Windows;
+using System.Xml.Linq;
+
+namespace ICSharpCode.ILSpy
+{
+ ///
+ /// Per-session setting:
+ /// Loaded at startup; saved at exit.
+ ///
+ public class SessionSettings
+ {
+ public SessionSettings()
+ {
+ XElement doc = ILSpySettings.LoadSettings("SessionSettings");
+
+ XElement filterSettings = doc.Element("FilterSettings");
+ if (filterSettings == null) filterSettings = new XElement("FilterSettings");
+
+ this.FilterSettings = new FilterSettings(filterSettings);
+
+ XElement activeTreeViewPath = doc.Element("ActiveTreeViewPath");
+ if (activeTreeViewPath != null) {
+ this.ActiveTreeViewPath = activeTreeViewPath.Elements().Select(e => (string)e).ToArray();
+ }
+
+ this.WindowState = FromString((string)doc.Element("WindowState"), WindowState.Normal);
+ this.WindowBounds = FromString((string)doc.Element("WindowBounds"), new Rect(10, 10, 750, 550));
+ }
+
+ public FilterSettings FilterSettings;
+
+ public string[] ActiveTreeViewPath;
+
+ public WindowState WindowState = WindowState.Normal;
+ public Rect WindowBounds;
+
+ public void Save()
+ {
+ XElement doc = new XElement("SessionSettings");
+ doc.Add(this.FilterSettings.SaveAsXml());
+ if (this.ActiveTreeViewPath != null) {
+ doc.Add(new XElement("ActiveTreeViewPath", ActiveTreeViewPath.Select(p => new XElement("Node", p))));
+ }
+ doc.Add(new XElement("WindowState", ToString(this.WindowState)));
+ doc.Add(new XElement("WindowBounds", ToString(this.WindowBounds)));
+ ILSpySettings.SaveSettings(doc);
+ }
+
+ static T FromString(string s, T defaultValue)
+ {
+ if (s == null)
+ return defaultValue;
+ try {
+ TypeConverter c = TypeDescriptor.GetConverter(typeof(T));
+ return (T)c.ConvertFromInvariantString(s);
+ } catch (FormatException) {
+ return defaultValue;
+ }
+ }
+
+ static string ToString(T obj)
+ {
+ TypeConverter c = TypeDescriptor.GetConverter(typeof(T));
+ return c.ConvertToInvariantString(obj);
+ }
+ }
+}