以编程方式将当前调试器附加到启动的进程

时间:2018-10-30 16:16:22

标签: c# debugging process

我从事的一个项目在测试期间启动了本地流程。除其他功能外,它还会启动运行.NET网站的IISExpress实例。

我可以通过将调试器手动附加到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 :(得分:0)

原来,调试器是作为本地进程而不是托管进程附加到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);
        }
    }
}