// // 2002-2005 AlphaSierraPapa // GNU General Public License // // $Revision$ // using System; using System.Collections; using System.Collections.Generic; using System.Drawing; using System.IO; using System.Windows.Forms; using DebuggerLibrary; using ICSharpCode.Core; using System.CodeDom.Compiler; using ICSharpCode.TextEditor; using ICSharpCode.TextEditor.Document; using ICSharpCode.SharpDevelop.Gui; using ICSharpCode.SharpDevelop.Project; using ICSharpCode.SharpDevelop.Services; using System.Runtime.Remoting; using System.Reflection; using System.Security.Policy; using System.Diagnostics; namespace ICSharpCode.SharpDevelop.Services { public class WindowsDebugger:IDebugger { bool useRemotingForThreadInterop = false; NDebugger debugger; bool isDebuggingCache = false; bool isProcessRunningCache = false; bool serviceInitialized = false; List exceptionHistory = new List(); public event EventHandler ExceptionHistoryModified; protected virtual void OnExceptionHistoryModified() { if (ExceptionHistoryModified != null) { ExceptionHistoryModified(this, EventArgs.Empty); } } public NDebugger DebuggerCore { get { return debugger; } } public bool ServiceInitialized { get { return serviceInitialized; } } public IList ExceptionHistory { get { return exceptionHistory.AsReadOnly(); } } public WindowsDebugger() { } #region IDebugger Members public bool IsDebugging { get { return isDebuggingCache; } } public bool IsProcessRunning { get { return isProcessRunningCache; } } public bool CanDebug(IProject project) { return true; } public void Start(ProcessStartInfo processStartInfo) { if (!serviceInitialized) { InitializeService(); } debugger.Start(processStartInfo.FileName, processStartInfo.WorkingDirectory, processStartInfo.Arguments); } public bool SupportsStart { get { return true; } } public void StartWithoutDebugging(ProcessStartInfo processStartInfo) { System.Diagnostics.Process process; process = new System.Diagnostics.Process(); process.StartInfo = processStartInfo; process.Start(); } public bool SupportsStartWithoutDebugging { get { return true; } } public void Stop() { debugger.Terminate(); } public bool SupportsStop { get { return true; } } // ExecutionControl: public void Break() { debugger.Break(); } public void Continue() { debugger.Continue(); } public bool SupportsExecutionControl { get { return true; } } // Stepping: public void StepInto() { debugger.StepInto(); } public void StepOver() { debugger.StepOver(); } public void StepOut() { debugger.StepOut(); } public bool SupportsStepping { get { return true; } } public event EventHandler DebugStarted; protected virtual void OnDebugStarted(EventArgs e) { if (DebugStarted != null) { DebugStarted(this, e); } } public event EventHandler IsProcessRunningChanged; protected virtual void OnIsProcessRunningChanged(EventArgs e) { if (IsProcessRunningChanged != null) { IsProcessRunningChanged(this, e); } } public event EventHandler DebugStopped; protected virtual void OnDebugStopped(EventArgs e) { if (DebugStopped != null) { DebugStopped(this, e); } } /// /// Gets the current value of the variable as string that can be displayed in tooltips. /// public string GetValueAsString(string variableName) { if (debugger == null || !debugger.IsCurrentProcessSafeForInspection) return null; VariableCollection collection = debugger.LocalVariables; if (collection == null) return null; foreach (Variable v in collection) { if (v.Name == variableName) { object val = v.Value; if (val == null) return ""; else if (val is string) return "\"" + val.ToString() + "\""; else return val.ToString(); } } return null; } public void Dispose() { Stop(); } #endregion public event System.EventHandler Initialize; public void InitializeService() { if (useRemotingForThreadInterop) { // This needs to be called before instance of NDebugger is created string path = RemotingConfigurationHelpper.GetLoadedAssemblyPath("Debugger.Core.dll"); new RemotingConfigurationHelpper(path).Configure(); } debugger = new NDebugger(); debugger.LogMessage += new EventHandler(LogMessage); debugger.DebuggerTraceMessage += new EventHandler(TraceMessage); debugger.ProcessStarted += new EventHandler(ProcessStarted); debugger.ProcessExited += new EventHandler(ProcessExited); debugger.DebuggingPaused += new EventHandler(DebuggingPaused); debugger.DebuggingResumed += new EventHandler(DebuggingResumed); debugger.BreakpointStateChanged += delegate (object sender, BreakpointEventArgs e) { RestoreSharpdevelopBreakpoint(e.Breakpoint); }; DebuggerService.BreakPointAdded += delegate (object sender, BreakpointBookmarkEventArgs e) { AddBreakpoint(e.BreakpointBookmark); }; DebuggerService.BreakPointRemoved += delegate (object sender, BreakpointBookmarkEventArgs e) { RemoveBreakpoint(e.BreakpointBookmark); }; DebuggerService.BreakPointChanged += delegate (object sender, BreakpointBookmarkEventArgs e) { RemoveBreakpoint(e.BreakpointBookmark); AddBreakpoint(e.BreakpointBookmark); }; DebuggerService.SetIPRequest += delegate (object sender, DebuggerService.SetIPArgs args) { SourcecodeSegment seg = debugger.CurrentThread.CurrentFunction.SetIP(args.filename, args.line + 1, args.column); }; RestoreNDebuggerBreakpoints(); isDebuggingCache = false; isProcessRunningCache = true; if (Initialize != null) { Initialize(this, null); } serviceInitialized = true; } void AddBreakpoint(BreakpointBookmark breakpointBookmark) { SourcecodeSegment seg = new SourcecodeSegment(breakpointBookmark.FileName, breakpointBookmark.LineNumber + 1); Breakpoint b = debugger.AddBreakpoint(seg, breakpointBookmark.IsEnabled); breakpointBookmark.Tag = b; } void RemoveBreakpoint(BreakpointBookmark breakpointBookmark) { Breakpoint b = breakpointBookmark.Tag as Breakpoint; if (b != null) { debugger.RemoveBreakpoint(b); } } void RestoreNDebuggerBreakpoints() { debugger.ClearBreakpoints(); foreach (BreakpointBookmark b in DebuggerService.Breakpoints) { AddBreakpoint(b); } } void RestoreSharpdevelopBreakpoint(Breakpoint breakpoint) { foreach (BreakpointBookmark sdBreakpoint in DebuggerService.Breakpoints) { if (sdBreakpoint.Tag == breakpoint) { sdBreakpoint.IsEnabled = breakpoint.Enabled; sdBreakpoint.FileName = breakpoint.SourcecodeSegment.SourceFullFilename; sdBreakpoint.LineNumber = breakpoint.SourcecodeSegment.StartLine - 1; } } } void LogMessage(object sender, MessageEventArgs e) { DebuggerService.PrintDebugMessage(">" + e.Message); } void TraceMessage(object sender, MessageEventArgs e) { DebuggerService.PrintDebugMessage(e.Message + "\n"); } void ProcessStarted(object sender, ProcessEventArgs e) { if (debugger.Processes.Count == 1) { OnDebugStarted(EventArgs.Empty); isDebuggingCache = true; } } void ProcessExited(object sender, ProcessEventArgs e) { if (debugger.Processes.Count == 0) { exceptionHistory.Clear(); OnDebugStopped(EventArgs.Empty); isDebuggingCache = false; } } void DebuggingPaused(object sender, DebuggingPausedEventArgs e) { isProcessRunningCache = false; OnIsProcessRunningChanged(EventArgs.Empty); if (e.Reason == PausedReason.Exception) { exceptionHistory.Add(debugger.CurrentThread.CurrentException); OnExceptionHistoryModified(); if (debugger.CurrentThread.CurrentException.ExceptionType != ExceptionType.DEBUG_EXCEPTION_UNHANDLED) { // Ignore the exception e.ResumeDebuggingAfterEvent(); return; } JumpToCurrentLine(); switch (ExceptionForm.Show(debugger.CurrentThread.CurrentException)) { case ExceptionForm.Result.Break: break; case ExceptionForm.Result.Continue: e.ResumeDebuggingAfterEvent(); return; case ExceptionForm.Result.Ignore: debugger.CurrentThread.InterceptCurrentException(); break; } } else { JumpToCurrentLine(); } } void DebuggingResumed(object sender, DebuggerEventArgs e) { isProcessRunningCache = true; DebuggerService.RemoveCurrentLineMarker(); } public void JumpToCurrentLine() { SourcecodeSegment nextStatement = debugger.NextStatement; if (nextStatement == null) { return; } DebuggerService.JumpToCurrentLine(nextStatement.SourceFullFilename, nextStatement.StartLine, nextStatement.StartColumn, nextStatement.EndLine, nextStatement.EndColumn); } } }