Tim Lloyd's answer works great. Here's a small modification that makes a console program that attaches a debugger to a program specified as a case-insensitive regular expression on the command line. This is quite simple, so only one instance of Visual Studio is assumed, and only one instance of the process that you want to connect to.
using System; using System.Linq; using System.Runtime.InteropServices; using System.Runtime.InteropServices.ComTypes; using System.Text.RegularExpressions; using EnvDTE; namespace VstAttach { internal static class Program { [DllImport("ole32.dll")] static extern int GetRunningObjectTable(int reserved, out IRunningObjectTable prot); [DllImport("ole32.dll")] static extern int CreateBindCtx(int reserved, out IBindCtx ppbc); private static void Main(string[] args) { if (args.Length == 0) throw new Exception("Syntax: VstAttach ProcessName (case insensitive regex)"); var vst = System.Diagnostics.Process.GetProcessesByName("devenv").FirstOrDefault(); if (vst == null) throw new Exception("Visual Studio not found."); var visualStudioProcessId = vst.Id; _DTE visualStudioInstance; if (TryGetVsInstance(visualStudioProcessId, out visualStudioInstance)) { var processToAttachTo = visualStudioInstance.Debugger.LocalProcesses .Cast<Process>() .FirstOrDefault(process => Regex.IsMatch(process.Name, args[0], RegexOptions.IgnoreCase)); if (processToAttachTo != null) { processToAttachTo.Attach(); } } } private static bool TryGetVsInstance(int processId, out _DTE instance) { var numFetched = IntPtr.Zero; IRunningObjectTable runningObjectTable; IEnumMoniker monikerEnumerator; var 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; } } }
source share