14

I am building an internal development tool to manage different processes commonly used in our development environment. The tool shows the list of the monitored processes, indicating their running state and allows to start or stop each process.

I'd like to add the functionality of attaching a debugger to a monitored process from my tool instead of going in Debug -> Attach to process in Visual Studio and finding the process.

My goal is to have something like Debugger.Launch() that would show a list of the available Visual Studio. I can't use Debugger.Launch(), because it launches the debugger on the process that makes the call. I would need something like Debugger.Launch(processId).

How do I achieve this functionality?

A solution could be to implement a command in each monitored process to call Debugger.Launch() when the command is received from the monitoring tool, but I would prefer something that does not require to modify the code of the monitored processes.

Side question:

When using Debugger.Launch(), instances of Visual Studio that already have a debugger attached are not listed. Visual Studio is not limited to one attached debugger, you can attach on multiple process when using DebugAttach to process.

How do I bypass this limitation when using Debugger.Launch() or an alternative?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Jeff Cyr
  • 4,774
  • 1
  • 28
  • 42

3 Answers3

15

A coworker ended up with a solution using DTE, and I posted the code on PasteBin.

The methods of interest are AttachVisualStudioToProcess and TryGetVsInstance

Source Code

public static void AttachVisualStudioToProcess(Process visualStudioProcess, Process applicationProcess)
{
    _DTE visualStudioInstance;

    if (TryGetVsInstance(visualStudioProcess.Id, out visualStudioInstance))
    {
        //Find the process you want the Visual Studio instance to attach to...
        DTEProcess processToAttachTo = visualStudioInstance.Debugger.LocalProcesses.Cast<DTEProcess>().FirstOrDefault(process => process.ProcessID == applicationProcess.Id);

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

private static bool TryGetVsInstance(int processId, out _DTE instance)
{
    IntPtr numFetched = IntPtr.Zero;
    IRunningObjectTable runningObjectTable;
    IEnumMoniker monikerEnumerator;
    IMoniker[] monikers = new IMoniker[1];

    GetRunningObjectTable(0, out runningObjectTable);
    runningObjectTable.EnumRunning(out monikerEnumerator);
    monikerEnumerator.Reset();

    while (monikerEnumerator.Next(1, monikers, numFetched) == 0)
    {
        IBindCtx ctx;
        CreateBindCtx(0, out ctx);

        string runningObjectName;
        monikers[0].GetDisplayName(ctx, null, out runningObjectName);

        object runningObjectVal;
        runningObjectTable.GetObject(monikers[0], out runningObjectVal);

        if (runningObjectVal is _DTE && runningObjectName.StartsWith("!VisualStudio"))
        {
            int currentProcessId = int.Parse(runningObjectName.Split(':')[1]);

            if (currentProcessId == processId)
            {
                instance = (_DTE)runningObjectVal;
                return true;
            }
        }
    }

    instance = null;
    return false;
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Jeff Cyr
  • 4,774
  • 1
  • 28
  • 42
  • Did you make a custom VS plugin for this? Or how did you "wire it up"? I have a similar need. I'm staring with your code here, but looking for how you wired it up in your end solution. Thanks. – granadaCoder Sep 10 '13 at 18:57
  • We did not make a VS plugin, we used that code in a custom tool that is monitoring our product processes. – Jeff Cyr Sep 18 '13 at 22:17
  • I'm using this code but I can't figure out how to tell VS to attach to managed code. The Attach to process dialogue box asks "Attach to:" where you can select Managed code rather than auto detect. This needs to be set when debugging IISExpress processes. Any idea how to select that in code? – Max Oct 29 '13 at 12:13
  • Auto-detect should work for IISExpress process, but if you really need to specify the engine, you can use Process2.Attach2, http://msdn.microsoft.com/en-us/library/envdte80.process2.attach2(v=vs.90).aspx – Jeff Cyr Nov 01 '13 at 14:21
  • To be noted: `TryGetVsInstance` will not return the `DTE` object of an instance of Visual Studio which was not started as an administrator, if the calling script is called from a process with elevated rights. – Erwin Mayer Jul 14 '15 at 10:02
12

WinDbg does the chain debugging for native code by default. If you want to launch another instance of Visual Studio, check Launch the Debugger Automatically on MSDN:

To automate the existing debugger, use Marshal.GetActiveObject to get the current EnvDTE.Debugger then let it attach to the process you just created.

Sometimes, you may need to debug the startup code for an application that is launched by another process. Examples include services and custom setup actions. In these scenarios, you can have the debugger launch and automatically attach when your application starts.

To setup an application to launch the debugger automatically

  1. Start the Registry Editor (regedit).

  2. In the Registry Editor, open the HKEY_LOCAL_MACHINE folder.

  3. Navigate to HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\currentversion\image file execution options.

  4. In the Image File Execution Options folder, locate the name of the application you want to debug, such as myapp.exe. If you cannot find the application you want to debug:

    a. Right-click the Image File Execution Options folder, and on the shortcut menu, click New Key.

    b. Right-click the new key, and on the shortcut menu, click Rename.

    c. Edit the key name to the name of your application; myapp.exe, in this example.

  5. Right-click the myapp.exe folder, and on the shortcut menu, click New String Value.

  6. Right-click the new string value, and on the shortcut menu, click Rename.

  7. Change the name to debugger.

  8. Right-click the new string value, and on the shortcut menu, click Modify. The Edit String dialog box appears.

  9. In the Value data box, type vsjitdebugger.exe.

  10. Click OK.

  11. From the Registry menu, click Exit.

  12. The directory containing vsjitdebugger.exe must be in your system path. To add it to the system path, follow these steps:

    a. Open the Control Panel in Classic view, and double-click System.

    b. Click Advanced System Settings.

    c. In System Properties, click the Advanced tab.

    d. On the Advanced tab, click Environment Variables.

    e. In the Environment Variables dialog box, under System variables, select Path, then click the Edit button.

    f. In the Edit System Variable dialog box, add the directory to the Variable value box. Use a semicolon to separate it from other entries in the list.

    g. Click OK to close the Edit System Variable dialog box.

    h. Click OK to close the Environment Variables dialog box.

    i. Click OK to close the System Properties dialog box.

Now, use any method to start your application. Visual Studio will start and load the application.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Sheng Jiang 蒋晟
  • 15,125
  • 2
  • 28
  • 46
  • The link you provided indicate how to start a process with the debugger attached. I want to attach the debugger on a process when it is already running. After reading the article I checked the documentation about vsjitdebugger and what I exactly what I needed: vsjitdebugger -p ProcessId. Thanks for pointing me into that direction. Any idea how to attach to a visual studio that is in debugging mode? The list of Visual Studio shown in "Visual Studio Just-in-time debugger" does not display them. – Jeff Cyr Oct 26 '09 at 20:15
  • What do you mean? attach a debugger to Visual Studio that is debugging something else? What is that good for? – Sheng Jiang 蒋晟 Oct 27 '09 at 02:39
  • I mean to debug multiple process using only one visual studio instance. It is possible to do it from "Debug -> Attach to process", but the JIT Debugger dialog doesn't shows instances of Visual Studio that are in debugging mode. – Jeff Cyr Oct 27 '09 at 18:47
  • In my case, this would be useful because the monitored processes share a common visual studio solution. This solution is pretty big and consume alot of memory, so using only one instance to debug multiple process saves alot of memory. – Jeff Cyr Oct 27 '09 at 18:51
  • Then you probably need a Visual Studio Extension to automate that. – Sheng Jiang 蒋晟 Oct 27 '09 at 22:31
  • @SelflessCoder I have this exact same problem, what was your solution in the end? Did you try VS automation or come up with some other workaround? – Matt Howells Nov 01 '11 at 18:12
  • @Matt Howells I updated the question with a solution that a coworker found. – Jeff Cyr Nov 03 '11 at 14:09
  • I'll post an answer on my own question then – Jeff Cyr Nov 03 '11 at 14:16
6

Here is some information about how you can programmatically attach the debugger to multiple processes:

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Vilas
  • 1,405
  • 12
  • 15
  • Whilst this may theoretically answer the question, [it would be preferable](http://meta.stackexchange.com/q/8259) to include the essential parts of the answer here, and provide the link for reference. – Kev Nov 03 '11 at 14:15