Не удается выполнить оператор с помощью VS Debugger Interop
Я пишу расширение отладки 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; }
}
Что я делаю неправильно или неправильно понимаю здесь?
Ответы
Ответ 1
Это старый вопрос, но в Google об этих проблемах так мало, я думал, что помогу. Некоторые важные соображения:
- Используйте GetExpresssion3 (TreatAsStatement: = True), если это возможно, вместо ExecuteStatement (я не смог нормально работать с ExecuteStatement).
- Нить, вызывающая ваш делегат (OnEnterBreakMode), - это тот же самый поток, который понадобится, чтобы запустить снова, чтобы выполнить ваше выражение или инструкцию. Поэтому вызовите метод GetExpression в новом потоке (Task.Run..)
-
Вам нужно будет контролировать и управлять значением Reason для OnEnterBreakMode. Первоначальный разум - это UnwindFromException для фактического необработанного исключения. Затем ожидается, что вы установите переменную, например tempStack = New System.Diagnostics.StackTrace(True). OnEnterBreakMode будет вызываться снова после выполнения этого оператора, но на этот раз с оценкой для причины. На этом этапе вы теперь вызываете все своих GetExpressions для сбора всех ваших данных без дополнительных вызовов OnEnterBreakMode.
Dim dte2 As EnvDTE80.DTE2 = GetGlobalService (GetType (EnvDTE.DTE))
Dim debugger5 as EnvDTE100.Debugger5 = Dte2.Debugger
Интересное наблюдение за дизайном: System.Diagnostics.StackTrace - очень странно разработанный класс в контексте остальной части платформы .NET, пока вам не придется работать над этим проектом, где вы извлекаете StackTrace с помощью этой самой техники и смотрите выгода от его иначе нечетной конструкции.
Ответ 2
Я много разбирался с отладкой Visual Studio, и конечная причина замораживания всегда была связана с обработкой потоков: VS позволяет запускать любую часть кода во время отладки только в основном потоке. Каждый другой поток отключается, и если ваш код отладки зависит от другого потока, он также замерзнет.
Мое предположение: вы инициализировали свой DTE в другом потоке, чем то, что вы отлаживаете.
Предполагаемый результат: метод Delegate пытается загрузить контекст инициализирующего потока, который отличается от отлаженного потока, и, следовательно, он будет заморожен.
Предлагаемое решение: Не используйте метод делегата. Они неявно ссылаются на исходный контекст исполнения. Вместо этого зарегистрируйте регулярный метод и повторите инициализацию своего DTE в этом контексте.