From 33d4843f5d543f8f3ad05fb38d54e5da5cfd5c06 Mon Sep 17 00:00:00 2001 From: Eusebiu Marcu Date: Sat, 5 Mar 2011 17:18:37 +0200 Subject: [PATCH] Use MEF for debugger commands. --- .../AvalonEdit/IconBarMargin.cs | 24 +- .../AvalonEdit/TextMarkerService.cs | 2 +- Debugger/ILSpy.Debugger/DebuggedType.cs | 2 +- .../Services/Debugger/WindowsDebugger.cs | 2 +- ILSpy/AboutPage.cs | 1 + ILSpy/Commands/DebuggerCommands.cs | 288 ++++++++++++++++++ ILSpy/ExportCommandAttribute.cs | 3 +- ILSpy/ILSpy.csproj | 1 + ILSpy/MainWindow.xaml.cs | 19 +- ILSpy/TextView/DecompilerTextView.cs | 6 +- ILSpy/TreeNodes/TypeTreeNode.cs | 2 +- 11 files changed, 325 insertions(+), 25 deletions(-) create mode 100644 ILSpy/Commands/DebuggerCommands.cs diff --git a/Debugger/ILSpy.Debugger/AvalonEdit/IconBarMargin.cs b/Debugger/ILSpy.Debugger/AvalonEdit/IconBarMargin.cs index c593fdcb1..f87bf6c51 100644 --- a/Debugger/ILSpy.Debugger/AvalonEdit/IconBarMargin.cs +++ b/Debugger/ILSpy.Debugger/AvalonEdit/IconBarMargin.cs @@ -57,10 +57,10 @@ namespace ILSpy.Debugger.AvalonEdit // create a dictionary line number => first bookmark Dictionary bookmarkDict = new Dictionary(); foreach (var bm in BookmarkManager.Bookmarks) { - if (DebuggedData.CurrentType == null || bm.Type.FullName != DebuggedData.CurrentType.FullName) + if (DebugData.CurrentType == null || bm.Type.FullName != DebugData.CurrentType.FullName) continue; if (bm is BreakpointBookmark && - ((BreakpointBookmark)bm).Language != DebuggedData.Language) + ((BreakpointBookmark)bm).Language != DebugData.Language) continue; int line = bm.LineNumber; @@ -119,8 +119,8 @@ namespace ILSpy.Debugger.AvalonEdit BookmarkBase result = null; foreach (BookmarkBase bm in BookmarkManager.Bookmarks) { if (bm.LineNumber == line && - DebuggedData.CurrentType != null && - bm.Type.FullName == DebuggedData.CurrentType.FullName) { + DebugData.CurrentType != null && + bm.Type.FullName == DebugData.CurrentType.FullName) { if (result == null || bm.ZOrder > result.ZOrder) result = bm; } @@ -189,11 +189,11 @@ namespace ILSpy.Debugger.AvalonEdit InvalidateVisual(); } - if (DebuggedData.CurrentType == null) + if (DebugData.CurrentType == null) return; BreakpointBookmark bm = BookmarkManager.Bookmarks.Find( - b => b.Type.FullName == DebuggedData.CurrentType.FullName && + b => b.Type.FullName == DebugData.CurrentType.FullName && b.LineNumber == GetLineFromMousePosition(e) && b is BreakpointBookmark) as BreakpointBookmark; @@ -226,24 +226,24 @@ namespace ILSpy.Debugger.AvalonEdit return; } if (e.ChangedButton == MouseButton.Left) { - if (DebuggedData.CurrentType != null) { + if (DebugData.CurrentType != null) { // check if the codemappings exists for this line - var storage = CodeMappings.GetStorage(DebuggedData.Language); + var storage = CodeMappings.GetStorage(DebugData.Language); uint token; - var instruction = storage.GetInstructionByTypeAndLine(DebuggedData.CurrentType.FullName, line, out token); + var instruction = storage.GetInstructionByTypeAndLine(DebugData.CurrentType.FullName, line, out token); if (instruction == null || instruction.ILInstructionOffset.From == 0) { - MessageBox.Show(string.Format("Missing code mappings for {0} at line {1}", DebuggedData.CurrentType.FullName, line), + MessageBox.Show(string.Format("Missing code mappings for {0} at line {1}", DebugData.CurrentType.FullName, line), "Code mappings", MessageBoxButton.OK, MessageBoxImage.Information); return; } // no bookmark on the line: create a new breakpoint DebuggerService.ToggleBreakpointAt( - DebuggedData.CurrentType, + DebugData.CurrentType, line, - DebuggedData.Language); + DebugData.Language); } } InvalidateVisual(); diff --git a/Debugger/ILSpy.Debugger/AvalonEdit/TextMarkerService.cs b/Debugger/ILSpy.Debugger/AvalonEdit/TextMarkerService.cs index 5ce69b137..7df2da927 100644 --- a/Debugger/ILSpy.Debugger/AvalonEdit/TextMarkerService.cs +++ b/Debugger/ILSpy.Debugger/AvalonEdit/TextMarkerService.cs @@ -45,7 +45,7 @@ namespace ILSpy.Debugger.AvalonEdit { if (e.Bookmark is MarkerBookmark) { var bm = (MarkerBookmark)e.Bookmark; - if (DebuggedData.CurrentType != null && DebuggedData.CurrentType.FullName.Equals(bm.Type.FullName, StringComparison.OrdinalIgnoreCase)) { + if (DebugData.CurrentType != null && DebugData.CurrentType.FullName.Equals(bm.Type.FullName, StringComparison.OrdinalIgnoreCase)) { // add bookmark for the current type DocumentLine line = codeEditor.Document.GetLineByNumber(bm.LineNumber); bm.Marker = bm.CreateMarker(this, line.Offset, line.Length); diff --git a/Debugger/ILSpy.Debugger/DebuggedType.cs b/Debugger/ILSpy.Debugger/DebuggedType.cs index 2424e09f5..e3769105f 100644 --- a/Debugger/ILSpy.Debugger/DebuggedType.cs +++ b/Debugger/ILSpy.Debugger/DebuggedType.cs @@ -25,7 +25,7 @@ namespace ILSpy.Debugger /// /// Contains the data important for debugger from the main application. /// - public static class DebuggedData + public static class DebugData { /// /// Gets or sets the current debugged type diff --git a/Debugger/ILSpy.Debugger/Services/Debugger/WindowsDebugger.cs b/Debugger/ILSpy.Debugger/Services/Debugger/WindowsDebugger.cs index dc153584e..037d67b96 100644 --- a/Debugger/ILSpy.Debugger/Services/Debugger/WindowsDebugger.cs +++ b/Debugger/ILSpy.Debugger/Services/Debugger/WindowsDebugger.cs @@ -49,7 +49,7 @@ namespace ILSpy.Debugger.Services private ConcurrentDictionary> CodeMappingsStorage { get { - return CodeMappings.GetStorage(DebuggedData.Language); + return CodeMappings.GetStorage(DebugData.Language); } } diff --git a/ILSpy/AboutPage.cs b/ILSpy/AboutPage.cs index 4eb58209d..2b2d1b7e8 100644 --- a/ILSpy/AboutPage.cs +++ b/ILSpy/AboutPage.cs @@ -29,6 +29,7 @@ namespace ICSharpCode.ILSpy public override void Execute(object parameter) { + MainWindow.Instance.UnselectAll(); Display(decompilerTextView); } diff --git a/ILSpy/Commands/DebuggerCommands.cs b/ILSpy/Commands/DebuggerCommands.cs new file mode 100644 index 000000000..c2e082630 --- /dev/null +++ b/ILSpy/Commands/DebuggerCommands.cs @@ -0,0 +1,288 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) +using System; +using System.Diagnostics; +using System.Linq; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Input; +using System.Windows.Interop; + +using ILSpy.Debugger; +using ILSpy.Debugger.Bookmarks; +using ILSpy.Debugger.Services; +using ILSpy.Debugger.UI; +using Microsoft.Win32; + +namespace ICSharpCode.ILSpy.Commands +{ + internal abstract class DebuggerCommands : SimpleCommand + { + public DebuggerCommands() + { + MainWindow.Instance.KeyUp += OnKeyUp; + } + + void OnKeyUp(object sender, KeyEventArgs e) + { + switch (e.Key) { + case Key.F5: + if (this is ContinueDebuggingCommand) { + ((ContinueDebuggingCommand)this).Execute(null); + e.Handled = true; + } + break; + case Key.System: + if (this is StepOverCommand) { + ((StepOverCommand)this).Execute(null); + e.Handled = true; + } + break; + case Key.F11: + if (this is StepIntoCommand) { + ((StepIntoCommand)this).Execute(null); + e.Handled = true; + } + break; + default: + // do nothing + break; + } + } + + #region Static members + [System.Runtime.InteropServices.DllImport("user32.dll")] + static extern bool SetWindowPos( + IntPtr hWnd, + IntPtr hWndInsertAfter, + int X, + int Y, + int cx, + int cy, + uint uFlags); + + const UInt32 SWP_NOSIZE = 0x0001; + const UInt32 SWP_NOMOVE = 0x0002; + + static readonly IntPtr HWND_BOTTOM = new IntPtr(1); + static readonly IntPtr HWND_TOP = new IntPtr(0); + + static void SendWpfWindowPos(Window window, IntPtr place) + { + var hWnd = new WindowInteropHelper(window).Handle; + SetWindowPos(hWnd, place, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE); + } + #endregion + + protected static IDebugger CurrentDebugger { + get { + return DebuggerService.CurrentDebugger; + } + } + + protected void StartDebugging(Process process) + { + CurrentDebugger.Attach(process); + EnableDebuggerUI(false); + CurrentDebugger.DebugStopped += OnDebugStopped; + CurrentDebugger.IsProcessRunningChanged += CurrentDebugger_IsProcessRunningChanged; + } + + protected void OnDebugStopped(object sender, EventArgs e) + { + EnableDebuggerUI(true); + CurrentDebugger.DebugStopped -= OnDebugStopped; + CurrentDebugger.IsProcessRunningChanged -= CurrentDebugger_IsProcessRunningChanged; + } + + protected void EnableDebuggerUI(bool enable) + { + var menuItems = MainWindow.Instance.mainMenu.Items; + var toolbarItems = MainWindow.Instance.toolBar.Items; + + // menu + var items = menuItems.OfType().Where(m => (m.Header as string) == "_Debugger"); + foreach (var item in items.First().Items.OfType()) { + string header = (string)item.Header; + if (header.StartsWith("Attach") || header.StartsWith("Debug")) + item.IsEnabled = enable; + else + item.IsEnabled = !enable; + } + + //toolbar + var buttons = toolbarItems.OfType public void Decompile(ILSpy.Language language, IEnumerable treeNodes, DecompilationOptions options) { - DebuggedData.CurrentType = null; + DebugData.CurrentType = null; // Some actions like loading an assembly list cause several selection changes in the tree view, // and each of those will start a decompilation action. bool isDecompilationScheduled = this.nextDecompilationRun != null; @@ -396,8 +396,8 @@ namespace ICSharpCode.ILSpy.TextView // show the currentline marker var bm = CurrentLineBookmark.Instance; - if (bm != null && DebuggedData.CurrentType != null) { - if (DebuggedData.CurrentType.FullName.Equals(bm.Type.FullName, StringComparison.OrdinalIgnoreCase)) { + if (bm != null && DebugData.CurrentType != null) { + if (DebugData.CurrentType.FullName.Equals(bm.Type.FullName, StringComparison.OrdinalIgnoreCase)) { DocumentLine line = textEditor.Document.GetLineByNumber(bm.LineNumber); bm.Marker = bm.CreateMarker(textMarkerService, line.Offset, line.Length); UnfoldAndScroll(bm.LineNumber); diff --git a/ILSpy/TreeNodes/TypeTreeNode.cs b/ILSpy/TreeNodes/TypeTreeNode.cs index d9f78ea8e..295add9c4 100644 --- a/ILSpy/TreeNodes/TypeTreeNode.cs +++ b/ILSpy/TreeNodes/TypeTreeNode.cs @@ -129,7 +129,7 @@ namespace ICSharpCode.ILSpy.TreeNodes public override void Decompile(Language language, ITextOutput output, DecompilationOptions options) { - DebuggedData.CurrentType = type; + DebugData.CurrentType = type; language.DecompileType(type, output, options); }