envdte не запускает некоторые события отладки
Я пытаюсь использовать envdte для связи с отладчиком Visual Studio. К сожалению, я не могу запустить события OnEnterBreakMode/OnEnterRunMode/OnEnterDesignMode. Событие OnContextChanged работает хорошо, но остальные не запускаются.
Ниже приведен мой код для воспроизведения проблемы консольного приложения C# (я пытался максимально упростить его)
Наиболее важным является класс Debugger. Я тестирую его таким образом: 1. Скомпилируйте код ниже 2. Откройте проект C++ в Visual Studio 3. Запустите скомпилированную программу из шага 1 4. Подключитесь к Visual Studio (введите 0 и введите) 5. Запустите отладку этого проекта C++ - запустите отладку, добавить точки останова шаг, шаг, шаг, f5 ...
Наконец, единственный вывод, который я могу получить, выглядит следующим образом:
Select Debugger Number:
0 - !VisualStudio.DTE.15.0:13000
0
Context Changed
Context Changed
Context Changed
Context Changed
Context Changed
Context Changed
Context Changed
Context Changed
Context Changed
Context Changed
Context Changed
Мой тестовый код:
using System;
using System.Collections.Generic;
using EnvDTE;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
namespace DebugWatchTest
{
class DebuggerConnector
{
[DllImport("ole32.dll")]
private static extern int CreateBindCtx(uint reserved, out IBindCtx ppbc);
public static List<string> FindDebuggers()
{
List<string> result = new List<string>();
IBindCtx bindCtx = null;
IRunningObjectTable rot = null;
IEnumMoniker enumMonikers = null;
try
{
Marshal.ThrowExceptionForHR(CreateBindCtx(reserved: 0, ppbc: out bindCtx));
bindCtx.GetRunningObjectTable(out rot);
rot.EnumRunning(out enumMonikers);
IMoniker[] moniker = new IMoniker[1];
IntPtr numberFetched = IntPtr.Zero;
while (enumMonikers.Next(1, moniker, numberFetched) == 0)
{
string name = null;
IMoniker runningObjectMoniker = moniker[0];
if (runningObjectMoniker != null)
{
try {
runningObjectMoniker.GetDisplayName(bindCtx, null, out name);
}
catch (UnauthorizedAccessException)
{ } // Do nothing, there is something in the ROT that we do not have access to.
}
const string progName = "!VisualStudio.DTE";
if (!string.IsNullOrEmpty(name) && name.StartsWith(progName, StringComparison.Ordinal))
{
result.Add(name);
}
}
}
finally
{
if (enumMonikers != null) {
Marshal.ReleaseComObject(enumMonikers);
}
if (rot != null) {
Marshal.ReleaseComObject(rot);
}
if (bindCtx != null) {
Marshal.ReleaseComObject(bindCtx);
}
}
return result;
}
public static DTE Connect(string debuggerName)
{
object runningObject = null;
IBindCtx bindCtx = null;
IRunningObjectTable rot = null;
IEnumMoniker enumMonikers = null;
try
{
Marshal.ThrowExceptionForHR(CreateBindCtx(reserved: 0, ppbc: out bindCtx));
bindCtx.GetRunningObjectTable(out rot);
rot.EnumRunning(out enumMonikers);
IMoniker[] moniker = new IMoniker[1];
IntPtr numberFetched = IntPtr.Zero;
while (enumMonikers.Next(1, moniker, numberFetched) == 0)
{
string name = null;
IMoniker runningObjectMoniker = moniker[0];
if (runningObjectMoniker != null)
{
try {
runningObjectMoniker.GetDisplayName(bindCtx, null, out name);
}
catch (UnauthorizedAccessException)
{ } // Do nothing, there is something in the ROT that we do not have access to.
}
if (!string.IsNullOrEmpty(name) && name.Equals(debuggerName, StringComparison.Ordinal))
{
Marshal.ThrowExceptionForHR(rot.GetObject(runningObjectMoniker, out runningObject));
break;
}
}
}
finally
{
if (enumMonikers != null) {
Marshal.ReleaseComObject(enumMonikers);
}
if (rot != null) {
Marshal.ReleaseComObject(rot);
}
if (bindCtx != null) {
Marshal.ReleaseComObject(bindCtx);
}
}
if (runningObject is DTE)
{
return runningObject as DTE;
}
return null;
}
}
class Debugger
{
DTE instance;
Events e;
DebuggerEvents de;
public Debugger(DTE d)
{
instance = d;
e = instance.Events;
de = e.DebuggerEvents;
de.OnContextChanged += De_OnContextChanged;
de.OnEnterBreakMode += De_OnEnterBreakMode;
de.OnEnterRunMode += De_OnModeChanged;
de.OnEnterDesignMode += De_OnModeChanged;
}
private void De_OnModeChanged(dbgEventReason Reason) {
Console.WriteLine("Mode Changed");
}
private void De_OnEnterBreakMode(dbgEventReason Reason, ref dbgExecutionAction ExecutionAction)
{
Console.WriteLine("BreakMode");
}
private void De_OnContextChanged(Process NewProcess, EnvDTE.Program NewProgram, Thread NewThread, StackFrame NewStackFrame)
{
Console.WriteLine("Context Changed");
}
}
class Program
{
static void Main(string[] args)
{
List<string> debuggers = DebuggerConnector.FindDebuggers();
Console.WriteLine("Select Debugger Number:");
for(int i = 0; i < debuggers.Count;++i)
Console.WriteLine($"{i} - {debuggers[i]}");
string number = Console.ReadLine();
string processId = debuggers[int.Parse(number)];
DTE msvc = DebuggerConnector.Connect(processId);
Debugger d = new Debugger(msvc);
while (true)
{ }
}
}
}
Aby намекает, что не так в моем коде?