我们正在开发一个开源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(至少我不知道在这种情况下如何做到这一点 - 我已经完成了我的研究(所以我相信:-))。抓取输出会对我们的扩展有一些显着的好处(我没有在这里列出 - 如果你感兴趣,请在评论中告诉我们),所以我们正在寻找一种不同的方法来处理这种情况。
那么我们如何运行可执行文件(包括抓取可执行文件的输出)和立即将调试器附加到它上面,这样就不会错过任何断点?这有可能吗?
答案 0 :(得分:1)
您可以使用CREATE_SUSPENDED创建标志启动您的调试对象(请参阅示例How to call CreateProcess()...)(有关详细信息,请参阅Creation Flags),然后在连接调试器后继续PInvoke ResumeThread。
您可能需要根据具体需要调整CreateProcess选项,但应该这样做。
<强>更新强>: 一个很多更好的选项,因为您正在编写VS扩展,是使用IVsDebugger4接口来调用LaunchDebugTargets4。界面记录在案,您可以在GitHub上找到大量示例(只需搜索LaunchDebugTargets4)。使用本机调试引擎附加后,此方法将避免VS中的麻烦中断。