Программно подключить текущий отладчик к запущенным процессам - PullRequest
0 голосов
/ 30 октября 2018

Один проект, над которым я работаю, запускает локальные процессы во время тестирования. Среди прочего он запускает экземпляр IISExpress, работающий на веб-сайте .NET.

Я могу отладить код веб-сайта, вручную подключив отладчик к процессу IISExpress. Тем не менее, я хотел бы автоматизировать этот ручной шаг.

Ниже приведен код, который у меня есть. Кажется, он находит процесс, к которому нужно присоединиться (то есть Attach2 называется). Однако точки останова в коде веб-сайта по-прежнему не достигаются даже после вызова Attach2 (они отображаются в виде красного круга с белой заливкой).

Что я делаю не так?

public class DebuggerHelper
{
    [DllImport("ole32.dll")]
    private static extern int CreateBindCtx(uint reserved, out IBindCtx ppbc);

    public static bool TryAttachProcessesToVisualStudioDebuggingCurrentProcess(params int[] processIds)
    {
        var notAttached = processIds.Length;
        var currentProcessId = System.Diagnostics.Process.GetCurrentProcess().Id;

        IBindCtx bindCtx = null;
        IRunningObjectTable runningObjectTable = null;
        IEnumMoniker enumMonikers = null;

        try
        {
            Marshal.ThrowExceptionForHR(CreateBindCtx(0, out bindCtx));
            bindCtx.GetRunningObjectTable(out runningObjectTable);
            runningObjectTable.EnumRunning(out enumMonikers);
            enumMonikers.Reset();

            var numFetched = IntPtr.Zero;
            var monikers = new IMoniker[1];
            while (enumMonikers.Next(1, monikers, numFetched) == 0)
            {
                monikers[0].GetDisplayName(bindCtx, null, out var runningObjectName);
                runningObjectTable.GetObject(monikers[0], out var runningObjectVal);

                if (runningObjectVal is EnvDTE80.DTE2 dte
                    && runningObjectName.StartsWith("!VisualStudio.DTE.15.0"))
                {
                    foreach (EnvDTE80.Process2 debuggedProcess in dte.Debugger.DebuggedProcesses)
                    {
                        if (debuggedProcess.ProcessID == currentProcessId)
                        {
                            foreach (EnvDTE80.Process2 localProcess in dte.Debugger.LocalProcesses)
                            {
                                if (processIds.Contains(localProcess.ProcessID))
                                {
                                    localProcess.Attach();
                                    notAttached--;
                                }
                            }
                        }
                    }
                }
            }

            return notAttached == 0;
        }
        finally
        {
            if (enumMonikers != null)
            {
                Marshal.ReleaseComObject(enumMonikers);
            }

            if (runningObjectTable != null)
            {
                Marshal.ReleaseComObject(runningObjectTable);
            }

            if (bindCtx != null)
            {
                Marshal.ReleaseComObject(bindCtx);
            }
        }
    }
}

Редактировать: Похоже, что он несколько привязан, но что-то не так. Я получаю следующее:

enter image description here

1 Ответ

0 голосов
/ 01 ноября 2018

Оказалось, что отладчик подключался к IISExpress как собственный процесс, а не как управляемый. После изменения кода вместо использования Attach2 с указанием управляемого он работает как положено.

Обновлен рабочий код (некоторые другие изменения, вероятно, не нужны и являются результатом процесса устранения неполадок):

public class DebugHelper
{
    [DllImport("ole32.dll")]
    static extern int GetRunningObjectTable(int reserved, out IRunningObjectTable prot);

    [DllImport("ole32.dll")]
    static extern int CreateBindCtx(int reserved, out IBindCtx ppbc);

    public static bool AttachTo(params int[] processIds)
    {
        var notAttached = processIds.Length;
        var maybeDebuggedProcessId = System.Diagnostics.Process.GetCurrentProcess().Id;

        IRunningObjectTable runningObjectTable = null;
        IEnumMoniker enumMoniker = null;
        IBindCtx bindCtx = null;

        try
        {
            CreateBindCtx(0, out bindCtx);
            GetRunningObjectTable(0, out runningObjectTable);
            runningObjectTable.EnumRunning(out enumMoniker);

            var monikers = new IMoniker[1];
            var numFetched = IntPtr.Zero;
            while (enumMoniker.Next(1, monikers, numFetched) == 0)
            {
                monikers[0].GetDisplayName(bindCtx, null, out var runningObjectName);
                runningObjectTable.GetObject(monikers[0], out var runningObjectVal);

                if (runningObjectVal is DTE2 dte
                    && dte.Debugger is Debugger2 debugger
                    && runningObjectName.StartsWith("!VisualStudio.DTE.15.0"))
                {
                    foreach (Process2 debuggedProcess in dte.Debugger.DebuggedProcesses)
                    {
                        if (debuggedProcess.ProcessID == maybeDebuggedProcessId)
                        {
                            var def = debugger.Transports.Item("Default");
                            var engines = new List<Engine>();
                            foreach (Engine engine in def.Engines)
                            {
                                engines.Add(engine);
                            }

                            var debugEngine = new[]
                            {
                                engines.Single(x => x.Name == "Managed (v4.6, v4.5, v4.0)")
                            };

                            foreach (Process2 localProcess in dte.Debugger.LocalProcesses)
                            {
                                if (processIds.Contains(localProcess.ProcessID))
                                {
                                    localProcess.Attach2(debugEngine);
                                    notAttached--;
                                }
                            }

                            break;
                        }
                    }
                }
            }
            return notAttached == 0;
        }
        finally
        {
            if (bindCtx != null) Marshal.ReleaseComObject(bindCtx);
            if (runningObjectTable != null) Marshal.ReleaseComObject(runningObjectTable);
            if (enumMoniker != null) Marshal.ReleaseComObject(enumMoniker);
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...