C#:附加调试器以干净的方式处理

时间:2016-08-11 06:36:48

标签: c# c++ visual-studio debugging process

我们正在开发一个开源Visual Studio extension,用于运行在VS中使用C ++ Google Test框架编写的测试。用于测试适配器的VS API的一部分是可以在附加调试器的情况下运行测试。但是,该API不允许获取正在执行的进程的输出:它只返回进程ID,而afaik,如果进程已在运行,则无法访问该输出。

因此,我们想要启动我们自己的进程,并将调试器附加到我们自己的进程(遵循接受的this question答案中描述的方法)。到目前为止,这是有效的,但我们有一个问题:似乎只有在进程已经运行时才能附加调试器,从而导致错过断点;原因似乎是断点可能已经传递,直到连接调试器。请注意,我们确实遇到了断点,因此这种方法似乎总体上起作用,但它并不完全可靠。

以下是启动流程的代码(其中command是Google Test框架生成的可执行文件):

var processStartInfo = new ProcessStartInfo(command, param)
{
    RedirectStandardOutput = true,
    RedirectStandardError = false,
    UseShellExecute = false,
    CreateNoWindow = true,
    WorkingDirectory = workingDirectory
};

Process process = new Process { StartInfo = processStartInfo };
process.Start()

DebuggerAttacher.AttachVisualStudioToProcess(vsProcess, vsInstance, process);

这是附加调试器的实用方法:

internal static void AttachVisualStudioToProcess(Process visualStudioProcess, _DTE visualStudioInstance, Process applicationProcess)
{
    //Find the process you want the VS instance to attach to...
    DTEProcess processToAttachTo = visualStudioInstance.Debugger.LocalProcesses.Cast<DTEProcess>().FirstOrDefault(process => process.ProcessID == applicationProcess.Id);

    //AttachDebugger to the process.
    if (processToAttachTo != null)
    {
        processToAttachTo.Attach();

        ShowWindow((int)visualStudioProcess.MainWindowHandle, 3);
        SetForegroundWindow(visualStudioProcess.MainWindowHandle);
    }
    else
    {
        throw new InvalidOperationException("Visual Studio process cannot find specified application '" + applicationProcess.Id + "'");
    }
}

有没有办法以更可靠的方式连接调试器?例如,是否可以从C#启动进程,以便进程在开始执行传递的命令之前等待1秒?这将给我们足够的时间来附加调试器(至少在我的机器上 - 我已经通过在Google Test可执行文件的main()方法上添加1s等待时间来测试这个,但这不是一个选项,因为我们的用户需要更改他们的测试代码,以便能够使用我们的扩展调试它... ...或者是否有一种干净的方式(所描述的方式可能明显失败,例如在慢速机器上)?

更新:让我们回顾一下问题陈述:我们的用户有一个C ++解决方案,包括用Google Test框架编写的测试(编译成可执行文件,例如从命令行运行)。我们提供了一个用C#(一个测试适配器)编写的VS扩展,它发现了可执行文件,在Process的帮助下运行它,收集测试结果,并在VS测试资源管理器中显示它们。现在,如果我们的用户单击 Debug tests ,我们将启动运行C ++可执行文件的过程,然后将调试器附加到该进程。但是,在将调试器附加到进程所花费的时间之后,可执行文件已经开始运行,并且已经执行了一些测试,导致这些测试中的断点被丢失。

因为我们不想强迫我们的用户更改他们的C ++代码(例如,在测试代码的main()方法的开头添加一些等待时间段,或者使用以下Hans引用的方法之一) ,我们需要一种不同的方式来附加该调试器。事实上,VS测试框架允许启动附加调试器的进程(并且该方法不会受到我们的问题 - 这就是我们现在正在做的事情),但是这种方法不允许抓取进程的输出,因为我们得到的只是是已经运行的进程的进程ID(至少我不知道在这种情况下如何做到这一点 - 我已经完成了我的研究(所以我相信:-))。抓取输出会对我们的扩展有一些显着的好处(我没有在这里列出 - 如果你感兴趣,请在评论中告诉我们),所以我们正在寻找一种不同的方法来处理这种情况。

那么我们如何运行可执行文件(包括抓取可执行文件的输出)和立即将调试器附加到它上面,这样就不会错过任何断点?这有可能吗?

1 个答案:

答案 0 :(得分:1)

您可以使用CREATE_SUSPENDED创建标志启动您的调试对象(请参阅示例How to call CreateProcess()...)(有关详细信息,请参阅Creation Flags),然后在连接调试器后继续PInvoke ResumeThread。

您可能需要根据具体需要调整CreateProcess选项,但应该这样做。

<强>更新: 一个很多更好的选项,因为您正在编写VS扩展,是使用IVsDebugger4接口来调用LaunchDebugTargets4。界面记录在案,您可以在GitHub上找到大量示例(只需搜索LaunchDebugTargets4)。使用本机调试引擎附加后,此方法将避免VS中的麻烦中断。