#develop (short for SharpDevelop) is a free IDE for .NET programming languages.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

230 lines
8.1 KiB

// Copyright (c) 2014 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.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using Debugger;
using ICSharpCode.Core.Presentation;
using Debugger.AddIn.TreeModel;
using ICSharpCode.Core;
using ICSharpCode.SharpDevelop.Services;
using ICSharpCode.SharpDevelop.Workbench;
namespace ICSharpCode.SharpDevelop.Gui.Pads
{
public class CallStackPad : AbstractPadContent
{
ListView listView;
public override object Control {
get { return this.listView; }
}
public CallStackPad()
{
var res = new CommonResources();
res.InitializeComponent();
listView = new ListView();
listView.View = (GridView)res["callstackGridView"];
listView.MouseDoubleClick += listView_MouseDoubleClick;
listView.SetValue(GridViewColumnAutoSize.AutoWidthProperty, "100%");
listView.ContextMenu = CreateMenu();
WindowsDebugger.RefreshingPads += RefreshPad;
RefreshPad();
}
ContextMenu CreateMenu()
{
MenuItem extMethodsItem = new MenuItem();
extMethodsItem.Header = ResourceService.GetString("MainWindow.Windows.Debug.CallStack.ShowExternalMethods");
extMethodsItem.IsChecked = DebuggingOptions.Instance.ShowExternalMethods;
extMethodsItem.Click += delegate {
extMethodsItem.IsChecked = DebuggingOptions.Instance.ShowExternalMethods = !DebuggingOptions.Instance.ShowExternalMethods;
WindowsDebugger.RefreshPads();
};
MenuItem moduleItem = new MenuItem();
moduleItem.Header = ResourceService.GetString("MainWindow.Windows.Debug.CallStack.ShowModuleNames");
moduleItem.IsChecked = DebuggingOptions.Instance.ShowModuleNames;
moduleItem.Click += delegate {
moduleItem.IsChecked = DebuggingOptions.Instance.ShowModuleNames = !DebuggingOptions.Instance.ShowModuleNames;
WindowsDebugger.RefreshPads();
};
MenuItem argNamesItem = new MenuItem();
argNamesItem.Header = ResourceService.GetString("MainWindow.Windows.Debug.CallStack.ShowArgumentNames");
argNamesItem.IsChecked = DebuggingOptions.Instance.ShowArgumentNames;
argNamesItem.Click += delegate {
argNamesItem.IsChecked = DebuggingOptions.Instance.ShowArgumentNames = !DebuggingOptions.Instance.ShowArgumentNames;
WindowsDebugger.RefreshPads();
};
MenuItem argValuesItem = new MenuItem();
argValuesItem.Header = ResourceService.GetString("MainWindow.Windows.Debug.CallStack.ShowArgumentValues");
argValuesItem.IsChecked = DebuggingOptions.Instance.ShowArgumentValues;
argValuesItem.Click += delegate {
argValuesItem.IsChecked = DebuggingOptions.Instance.ShowArgumentValues = !DebuggingOptions.Instance.ShowArgumentValues;
WindowsDebugger.RefreshPads();
};
MenuItem lineItem = new MenuItem();
lineItem.Header = ResourceService.GetString("MainWindow.Windows.Debug.CallStack.ShowLineNumber");
lineItem.IsChecked = DebuggingOptions.Instance.ShowLineNumbers;
lineItem.Click += delegate {
lineItem.IsChecked = DebuggingOptions.Instance.ShowLineNumbers = !DebuggingOptions.Instance.ShowLineNumbers;
WindowsDebugger.RefreshPads();
};
return new ContextMenu() {
Items = {
extMethodsItem,
new Separator(),
moduleItem,
argNamesItem,
argValuesItem,
lineItem
}
};
}
void listView_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
CallStackItem item = listView.SelectedItem as CallStackItem;
if ((item == null) || (item.Frame == null))
return;
if (item.Frame.Process.IsPaused) {
if (item.Frame != null) {
WindowsDebugger.CurrentStackFrame = item.Frame;
WindowsDebugger.Instance.JumpToCurrentLine();
WindowsDebugger.RefreshPads();
}
} else {
MessageService.ShowMessage("${res:MainWindow.Windows.Debug.CallStack.CannotSwitchWhileRunning}", "${res:MainWindow.Windows.Debug.CallStack.FunctionSwitch}");
}
}
void RefreshPad()
{
Thread thread = WindowsDebugger.CurrentThread;
if (thread == null) {
listView.ItemsSource = null;
} else {
var items = new ObservableCollection<CallStackItem>();
bool previousItemIsExternalMethod = false;
WindowsDebugger.CurrentProcess.EnqueueForEach(
listView.Dispatcher,
thread.GetCallstack(100),
f => items.AddIfNotNull(CreateItem(f, ref previousItemIsExternalMethod))
);
listView.ItemsSource = items;
}
}
CallStackItem CreateItem(StackFrame frame, ref bool previousItemIsExternalMethod)
{
bool showExternalMethods = DebuggingOptions.Instance.ShowExternalMethods;
var symSource = WindowsDebugger.PdbSymbolSource;
bool hasSymbols = symSource.Handles(frame.MethodInfo)
&& !symSource.IsCompilerGenerated(frame.MethodInfo)
&& frame.NextStatement != null && !string.IsNullOrWhiteSpace(frame.NextStatement.Filename);
if (showExternalMethods || hasSymbols) {
// Show the method in the list
previousItemIsExternalMethod = false;
return new CallStackItem() {
Frame = frame,
ImageSource = SD.ResourceService.GetImageSource("Icons.16x16.Method"),
Name = GetFullName(frame, hasSymbols),
HasSymbols = hasSymbols,
};
} else {
// Show [External methods] in the list
if (previousItemIsExternalMethod)
return null;
previousItemIsExternalMethod = true;
return new CallStackItem() {
Name = ResourceService.GetString("MainWindow.Windows.Debug.CallStack.ExternalMethods"),
HasSymbols = false
};
}
}
static string GetFullName(StackFrame frame, bool hasSymbols)
{
StringBuilder name = new StringBuilder(64);
if (DebuggingOptions.Instance.ShowModuleNames) {
name.Append(frame.MethodInfo.ToString());
name.Append('!');
}
name.Append(frame.MethodInfo.DeclaringType.FullName);
name.Append('.');
name.Append(frame.MethodInfo.Name);
if (DebuggingOptions.Instance.ShowArgumentNames || DebuggingOptions.Instance.ShowArgumentValues) {
name.Append('(');
for (int i = 0; i < frame.MethodInfo.Parameters.Count; i++) {
if (DebuggingOptions.Instance.ShowArgumentNames) {
name.Append(frame.MethodInfo.Parameters[i].Name);
if (DebuggingOptions.Instance.ShowArgumentValues) {
name.Append('=');
}
}
if (DebuggingOptions.Instance.ShowArgumentValues) {
try {
name.Append(frame.GetArgumentValue(i, hasSymbols).AsString(100));
} catch (GetValueException) {
name.Append(ResourceService.GetString("Global.NA"));
}
}
if (i < frame.ArgumentCount - 1) {
name.Append(", ");
}
}
name.Append(')');
}
if (DebuggingOptions.Instance.ShowLineNumbers) {
if (frame.NextStatement != null) {
name.Append(':');
name.Append(frame.NextStatement.StartLine.ToString());
}
}
return name.ToString();
}
}
public class CallStackItem
{
public StackFrame Frame { get; set; }
public ImageSource ImageSource { get; set; }
public string Name { get; set; }
public bool HasSymbols { get; set; }
public Brush FontColor {
get { return this.HasSymbols ? Brushes.Black : Brushes.Gray; }
}
}
}