using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace VsDebugger { /// /// I found this gem originally on PasteBin (http://pastebin.com/pHWMP3EQ) and (http://pastebin.com/KKyBpWQW). /// Since it was dropped there anonymously, it had little documentation, and I made a change, I thought I'd migrate it to a gist. /// I found this snippet of code extremely useful, it flows much better than the alternative Debugger.Launch() call. /// /// Example usage: /// /// /// /// Attaches a debugger, if built in with DEBUG symbol /// /// /// [Conditional("DEBUG")] /// private static void AttachDebugger() /// { /// if (!Debugger.IsAttached) /// { /// // do a search for any Visual Studio processes that also have our solution currently open /// var vsProcess = /// VisualStudioAttacher.GetVisualStudioForSolutions( /// new List() { "FooBar2012.sln", "FooBar.sln" }); /// /// if (vsProcess != null) /// { /// VisualStudioAttacher.AttachVisualStudioToProcess(proc, Process.GetCurrentProcess()); /// } /// else /// { /// // try and attach the old fashioned way /// Debugger.Launch(); /// } /// /// if (Debugger.IsAttached) /// { /// Console.WriteLine("\t>>> Attach sucessful"); /// } /// } /// } /// using System.IO; using EnvDTE; using DTEProcess = EnvDTE.Process; using System; using System.Collections.Generic; using System.Diagnostics; using Process = System.Diagnostics.Process; using System.Linq; using System.Runtime.InteropServices; using System.Runtime.InteropServices.ComTypes; using System.Runtime.InteropServices; using System.Diagnostics; namespace AppController { #region Classes public static class VisualStudioAttacher { #region Public Methods [DllImport("User32")] private static extern int ShowWindow(int hwnd, int nCmdShow); [DllImport("ole32.dll")] public static extern int CreateBindCtx(int reserved, out IBindCtx ppbc); [DllImport("ole32.dll")] public static extern int GetRunningObjectTable(int reserved, out IRunningObjectTable prot); [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] public static extern bool SetForegroundWindow(IntPtr hWnd); [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] public static extern IntPtr SetFocus(IntPtr hWnd); public static string GetSolutionForVisualStudio(Process visualStudioProcess) { _DTE visualStudioInstance; if (TryGetVsInstance(visualStudioProcess.Id, out visualStudioInstance)) { try { return visualStudioInstance.Solution.FullName; } catch (Exception) { } } return null; } public static Process GetAttachedVisualStudio(Process applicationProcess) { IEnumerable visualStudios = GetVisualStudioProcesses(); foreach (Process visualStudio in visualStudios) { _DTE visualStudioInstance; if (TryGetVsInstance(visualStudio.Id, out visualStudioInstance)) { try { foreach (Process debuggedProcess in visualStudioInstance.Debugger.DebuggedProcesses) { if (debuggedProcess.Id == applicationProcess.Id) { return debuggedProcess; } } } catch (Exception) { } } } return null; } public static void AttachVisualStudioToProcess(Process visualStudioProcess, Process applicationProcess) { _DTE visualStudioInstance; if (TryGetVsInstance(visualStudioProcess.Id, out visualStudioInstance)) { //Find the process you want the VS instance to attach to... DTEProcess processToAttachTo = visualStudioInstance.Debugger.LocalProcesses.Cast().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 + "'"); } } } public static Process GetVisualStudioForSolutions(List solutionNames) { foreach (string solution in solutionNames) { Process visualStudioForSolution = GetVisualStudioForSolution(solution); if (visualStudioForSolution != null) { return visualStudioForSolution; ; } } return null; } public static Process GetVisualStudioForSolution(string solutionName) { IEnumerable visualStudios = GetVisualStudioProcesses(); foreach (Process visualStudio in visualStudios) { _DTE visualStudioInstance; if (TryGetVsInstance(visualStudio.Id, out visualStudioInstance)) { try { string actualSolutionName = Path.GetFileName(visualStudioInstance.Solution.FullName); if (string.Compare(actualSolutionName, solutionName, StringComparison.InvariantCultureIgnoreCase) == 0) { return visualStudio; } } catch (Exception) { } } } return null; } #endregion #region Private Methods private static IEnumerable GetVisualStudioProcesses() { Process[] processes = Process.GetProcesses(); return processes.Where(o => o.ProcessName.Contains("devenv")); } 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; } #endregion } #endregion } }