c#:以一种干净的方式将调试器附加到进程

本文关键字:方式 调试器 进程 一种 | 更新日期: 2023-09-27 18:02:06

我们正在开发一个开源的Visual Studio扩展,用于在VS中运行用c++ Google Test框架编写的测试。部分用于测试适配器的VS API是附带调试器运行测试的可能性。但是,该API不允许获取正在执行的进程的输出:它只返回进程id,而且如果进程已经在运行,则无法访问该输出。

因此,我们想要启动我们自己的进程,并为我们自己的进程附加一个调试器(遵循这个问题的公认答案中描述的方法)。到目前为止,这是有效的,但我们有一个问题:似乎只有在进程已经运行时才可能附加调试器,这会导致错过断点;原因似乎是,在附加调试器之前,可能已经传递了断点。请注意,我们确实遇到了断点,所以这种方法似乎在一般情况下是有效的,但它并不完全可靠。

下面是启动进程的代码(其中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#启动一个进程,使进程在开始执行传递的命令之前等待,比如说,15秒?这将给我们足够的时间来附加调试器(至少在我的机器上-我已经通过在Google Test可执行文件的main()方法上添加15个等待期来测试这一点,但这不是一个选项,因为我们的用户需要更改他们的测试代码以便能够使用我们的扩展进行调试)…或者是否存在一种干净的方法(所描述的方法可能会明显失败,例如在慢速机器上)?

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

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

那么我们如何运行可执行文件(包括获取可执行文件的输出)并且立即为其附加调试器,这样就不会错过断点?这可能吗?

c#:以一种干净的方式将调试器附加到进程

你可以PInvoke CreateProcess(参见示例如何调用CreateProcess()…)启动你的debuggee使用CREATE_SUSPENDED创建标志(见创建标志更多细节),然后PInvoke ResumeThread继续一旦你的调试器连接。

您可能需要调整CreateProcess选项,这取决于您的具体需求,但应该这样做。

:一个更好的选择,因为你正在写一个VS扩展,是使用IVsDebugger4接口调用LaunchDebugTargets4。该接口有文档记录,您可以在GitHub上找到大量示例(只需搜索LaunchDebugTargets4)。这个方法可以避免在VS中使用本地调试引擎时出现的麻烦。