0

We are developing an open source Visual Studio extension for running tests written with the C++ Google Test framework within VS. Part of the VS API for test adapters is the possibility to run tests with a debugger attached. However, that API does not allow to grab the output of the executing process: It only returns the process id, and afaik, there's no way to access that output if the process is already running.

Thus, we'd like to launch our own process, and attach a debugger to that process on our own (following the approach described in the accepted answer of this question). This works so far, but we have one issue: It seems that attaching a debugger is only possible if the process already runs, resulting in missed breakpoints; the reason seems to be that the breakpoints might already be passed until the debugger is attached. Note that we indeed hit breakpoints, so the approach seems to work in general, but it's not exactly reliable.

Here's the code for launching the process (where command is the executable produced by the Google Test framework):

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);

And here's the utility method for attaching the debugger:

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 + "'");
    }
}

Is there any way to attach a debugger in a more reliable manner? For instance, is it possible to launch a process from C# such that the process will wait for, say, 1s before starting to execute the passed command? That would give us enough time to attach the debugger (at least on my machine - I've tested this by adding a 1s wait period at the main() method of the Google Test executable, but that's not an option, since our users would need to change their test code in order to be able to debug it with our extension)... Or is there even a clean way (the described way might obviously fail e.g. on slow machines)?

Update: Let's recap the problem statement: Our users have a C++ solution including tests written with the Google Test framework (which are compiled into an executable to be run e.g. from the command line). We provide a VS extension written in C# (a test adapter) which discovers the executable, runs it with the help of a Process, collects the test results, and displays them within the VS test explorer. Now, if our users click Debug tests, we are starting the process running the C++ executable and then attach a debugger to that process. However, by the time it takes to attach the debugger to the process, the executable has already started running, and some tests have already been executed, resulting in breakpoints within those tests being missed.

Since we do not want to force our users to change their C++ code (e.g. by adding some waiting period at the begin of main() method of the test code, or with one of the approaches referenced by Hans below), we need a different way to attach that debugger. In fact, the VS test framework allows to launch a process with a debugger attached (and that approach does not suffer from our problem - that's what we are doing now), but that approach does not allow grabbing the process' output since all we get is the process id of an already running process (at least I don't know how that can be done in this case - I have done my research on that (so I believe :-) ). Grabbing the output would have some significant benefits to our extension (which I do not list here - let me know in the comments if you are interested), so we are looking for a different way to handle such situations.

So how can we run the executable (including grabbing the executable's output) and immediately attach a debugger to it, such that no breakpoints are missed? Is that possible at all?

Community
  • 1
  • 1
csoltenborn
  • 1,127
  • 1
  • 12
  • 22
  • http://stackoverflow.com/a/3575068/17034 – Hans Passant Aug 11 '16 at 08:22
  • I do not understand how the things mentioned in your reference would solve our problem. Mutex and __debugbreak() would require modifying the code under test, which is not option, as I said (although cleaner than waiting in the code under test for a fixed time). I doubt that I can attach a debugger more quickly than our code can :-) (option 1 of your answer), and even if I could, it would be way to much burden to our users. The other of your options are not at all suited for our problem. Or am I missing something? Is my problem description lacking precision? – csoltenborn Aug 11 '16 at 17:07
  • @csoltenborn, how about using the Debugger.IsAttached property? It could help us check whether the debugger is attached to one process, for example, if you need to run other actions before attaching to it, you could stop it firstly. Or use the Condition breakpoint to handle the missing breakpoint hit as a workaround: https://msdn.microsoft.com/en-us/library/7sye83ce(v=vs.100).aspx – Jack Zhai Aug 12 '16 at 09:24
  • @JackZhai Thanks for your suggestion, but I again do not see how that might help us. Debugger.IsAttached needs to be called on the process to be debugged, which is a native .exe I can't change. I know about conditional breakpoints, but I do not see how they can help... And how can I stop a running process (unless a debugger is already attached)? Looks like I need to improve my problem description... if I missed something, please let me know (maybe after reading my improved problem statement)! – csoltenborn Aug 12 '16 at 17:34
  • And btw, thanks also for your suggestion, @HansPassant – csoltenborn Aug 12 '16 at 17:35
  • 1
    Have you thought about PInvoking CreateProcess and pass the creation flag to start the process suspended? – John Aug 13 '16 at 06:03
  • @John No, I haven't - didn't know about that, but it certainly sounds more promising than the other suggestions. I will check this out - in case you have some pointers to appropriate example code, feel free to add them :-) Thanks anyways! – csoltenborn Aug 13 '16 at 06:21

1 Answers1

1

You can PInvoke CreateProcess (see example How to call CreateProcess()...) to launch your debuggee using the CREATE_SUSPENDED creation flag (see Creation Flags for more detail) and then PInvoke ResumeThread to continue once your debugger is attached.

You may need to tweak the options to CreateProcess, depending on your specific needs, but that should do it.

Update: A much better option, since you are writing a VS extension, is to use IVsDebugger4 interface to call LaunchDebugTargets4. The interface is documented and you can find plenty of examples on GitHub (just search for LaunchDebugTargets4). This method will avoid that pesky break in VS once you attach with the native debug engine.

Community
  • 1
  • 1
John
  • 1,379
  • 8
  • 16
  • Works in general, thanks once more. There's one remaining problem (with which we can maybe live): VS shows a "exe has triggered a breakpoint" window before triggering the first breakpoint or even if no breakpoint is set (most likely because the process is suspended at the moment we attach the VS debugger). I'll accept your answer as soon as we are sure that this is the way to go. – csoltenborn Aug 15 '16 at 05:58