无法使用VS Debugger Interop执行语句

时间:2015-02-14 10:56:07

标签: c# debugging visual-studio-2013 visual-studio-extensions envdte

我正在编写一个调试器扩展VSPackage,我想在遇到断点时在调试过程中执行一个语句。在我的扩展程序代码中,我有这个:

void Initialize()
{
    // ...standard vspackage init code omitted...

    Globals.Init((DTE2)GetService(typeof(DTE)));              
    Globals.DebuggerEvents.OnEnterBreakMode += (dbgEventReason reason, ref dbgExecutionAction action) =>
    {
        try
        {
           var e1 = Globals.Application.Debugger.GetExpression("1+2");
           Debug.WriteLine(e1.Value);     // Prints "3"

           Globals.Application.Debugger.ExecuteStatement("x = 1+2", 1000);
           Debug.WriteLine("OK");         // Never prints this                          
        } 
        catch (Exception ex)
        {
           Debug.WriteLine("Error: "+ex); // Nor this
        }
    }             
}

在VS实例中调试此扩展时,我加载一个看起来像这样的简单程序

static void Main()
{
   int x = 5;
   Console.WriteLine("X is "+x); // Breakpoint on this line
}

当在调试过程中遇到断点时,调用处理程序并且扩展的输出窗口显示“3”,因此评估表达式有效,但它永远不会成功执行该语句。输出窗口中不会再打印任何内容。没有异常或超时发生,我无法继续调试过程,调试器似乎已崩溃。

globals类只保存DTE和DebuggerEvents

public static class Globals
{
   public static void Init(DTE2 dte)
   {
      Application = dte;
      DebuggerEvents = dte.Events.DebuggerEvents;    
   }

   public static DTE2 Application { get; private set; }
   public static DebuggerEvents DebuggerEvents { get; private set; }
}

我做错了什么,或者误解了?

2 个答案:

答案 0 :(得分:1)

这是一个老问题,但谷歌关于这些问题的情况很少,我想我会提供一些帮助。一些重要的考虑因素:

  1. 如果可能,请使用GetExpresssion3(TreatAsStatement:= True),而不是ExecuteStatement(我无法使ExecuteStatement正常工作)。
  2. 调用您的委托的线程(OnEnterBreakMode)是为了执行您的表达式或语句而需要再次运行的线程。因此,在新线程(Task.Run ..)
  3. 上调用GetExpression方法
  4. 您必须监控和管理OnEnterBreakMode的Reason值。对于实际的未处理异常,最初的Reason是UnwindFromException。然后,预计您正在设置变量,例如tempStack = New System.Diagnostics.StackTrace(True)。执行此语句后将再次调用OnEnterBreakMode,但这次使用的是Reason的原因。此时,您现在可以调用所有的GetExpressions来收集所有数据,而无需额外的OnEnterBreakMode调用。

    Dim dte2 As EnvDTE80.DTE2 = GetGlobalService(GetType(EnvDTE.DTE))

    将调试器5调暗为EnvDTE100.Debugger5 = Dte2.Debugger

  5. 有趣的设计观察:System.Diagnostics.StackTrace在.NET框架的其余部分的上下文中是一个非常奇怪的设计类,直到你必须处理这个项目,你通过这个技术提取StackTrace并看到其奇特设计的好处。

答案 1 :(得分:0)

我在使用Visual Studio调试时经常修补,而冻结的最终原因始终与线程处理有关:VS允许任何代码段在仅在主线程中进行调试时运行。每个其他线程都被禁用,如果您的调试代码依赖于不同的线程,它也会冻结。

我的猜测:你在与调试不同的线程中初始化了你的DTE。

假设结果:Delegate方法尝试加载与调试线程不同的初始化线程的上下文,因此它必然会被冻结。

建议的解决方案:不要使用委托方法。它们隐式地引用回原始执行上下文。而是注册常规方法,并在该上下文中重新初始化您的DTE。