Запуск экземпляров Visual Studio 2010 и программное присоединение к процессу?
У меня есть приложение WinForms (.net 3.5), которое отображает список процессов.
Я хотел бы иметь возможность подключиться к одному из этих процессов. У меня запущено несколько экземпляров Visual Studio 2010, и я хотел бы создать список/выпадающее меню, где я выбираю один из этих экземпляров, а затем присоединяю к нему отладчик.
Получение экземпляров VS2010 не должно быть слишком сложным, но я понятия не имею, как вызвать команду "attach to process". Я хочу, чтобы избежать sendkeys будет-тип решения, поэтому мне просто интересно, есть ли какой-то способ сделать это?
Edit: для уточнения: я хочу использовать конкретный запуск VS2010 для отладки внешнего приложения.
2 ответа:
Один из подходов заключается в использовании EnvDTE, который является интерфейсом автоматизации COM для Visual Studio:
Http://msdn.microsoft.com/en-us/library/envdte (VS.100).aspx
Вы можете получить интерфейсы автоматизации для запуска экземпляров Visual Studio, порыбачив в таблице Running Objects (ROT). После того, как у вас есть экземпляр интерфейса, вы можете автоматизировать выбранный экземпляр Visual Studio для присоединения к процессу, который вы хотите.
Ниже приведен основной пример того, как сделать это. Вам нужно будет добавить ссылку на ваш проект в EnvDTE. Эта сборка находится в следующем месте на моей машине:
C:\Program файлы (x86)\Microsoft Visual Studio 10.0\Common7\IDE\PublicAssemblies\EnvDTE.dll
Обновлено
Обновлено, чтобы привести пример получения интерфейса автоматизации экземпляра Visual Studio по идентификатору процесса.
using System; using System.Runtime.InteropServices; using System.Runtime.InteropServices.ComTypes; using EnvDTE; namespace VS2010EnvDte { internal class Program { [DllImport("ole32.dll")] public static extern int GetRunningObjectTable(int reserved, out IRunningObjectTable prot); [DllImport("ole32.dll")] public static extern int CreateBindCtx(int reserved, out IBindCtx ppbc); private static void Main() { //ProcessId of the VS instance - hard-coded here. int visualStudioProcessId = 5520; _DTE visualStudioInstance; if (TryGetVSInstance(visualStudioProcessId, out visualStudioInstance)) { Process processToAttachTo = null; //Find the process you want the VS instance to attach to... foreach (Process process in visualStudioInstance.Debugger.LocalProcesses) { if (process.Name == @"C:\Users\chibacity\AppData\Local\Google\Chrome\Application\chrome.exe") { processToAttachTo = process; break; } } //Attach to the process. if (processToAttachTo != null) { processToAttachTo.Attach(); } } } 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; } } }
Ответ Тима Ллойда отлично работает. Вот небольшая модификация, которая делает консольную программу, которая присоединяет отладчик к программе, указанной в командной строке как регулярное выражение без учета регистра. Это довольно просто, поэтому предполагается, что работает только один экземпляр Visual Studio и только один экземпляр процесса, к которому вы хотите подключиться.
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; } } }