C# Can';t使用VS调试器互操作执行语句

C# Can';t使用VS调试器互操作执行语句,c#,debugging,visual-studio-2013,visual-studio-extensions,envdte,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 += (dbgEventRe

我正在编写一个调试器扩展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; }
}

我做错了什么,还是误解了

我对VisualStudio调试做了很多修改,冻结的最终原因总是与线程处理有关:VS允许在只在主线程中调试时运行任何代码。其他线程都被禁用,如果调试代码依赖于不同的线程,它也将冻结

我猜:您在与正在调试的线程不同的线程中初始化了DTE

假设结果:委托方法尝试加载与调试线程不同的初始化线程的上下文,因此它肯定会被冻结


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

这是一个老问题,但是Google上关于这些问题的信息太少了,我想我应该提供一些帮助。一些重要的考虑:

  • 如果可能,使用getExpression3(TreatAsStatement:=True)代替ExecuteStatement(我无法使ExecuteStatement正常工作)
  • 调用委托的线程(OnInterBreakMode)与执行表达式或语句需要再次运行的线程相同。因此,在新线程(Task.Run..)上调用GetExpression方法
  • 您必须监视和管理OneInterBreakMode的原因值。初始原因是实际未处理异常的UnwindFromException。然后,您需要设置一个变量,例如tempStack=New System.Diagnostics.StackTrace(True)。执行此语句后,将再次调用OneInterbreakMode,但这一次由于计算原因。此时,您现在可以调用GetExpressions的all来收集all数据,而无需额外的OneInterbreakMode调用

    将dte2调整为EnvDTE80.dte2=GetGlobalService(GetType(EnvDTE.DTE))

    Dim debugger5作为EnvDTE100.debugger5=Dte2.Debugger


  • 有趣的设计观察:System.Diagnostics.StackTrace在.NET框架的其余部分中是一个设计非常奇怪的类,直到您必须在这个项目中使用这种技术提取StackTrace,并看到它的其他奇怪设计的好处

    这里最好假设调试器引擎尚未处于可以开始执行命令的状态。标准的技巧是稍后使用计时器或ThreadPool.QueueUserWorkItem()来执行此操作,以便稍后执行。延迟此操作在某种程度上有助于它有时执行表达式。我有一种感觉,重新进入处理程序可能会扼杀它,好像ExecuteStatement立即引发OnInterbreakMode(这可以解释为什么什么都不会发生,除非您稍微延迟它)。