2010-07-16 128 views
3

我有一个显示进程列表的WinForms应用程序(.net 3.5)。运行Visual Studio 2010实例并以编程方式附加到进程?

我想能够连接到这些过程之一。我有多个Visual Studio 2010实例正在运行,我想创建一个List/Dropdown,在其中选择其中一个实例,然后将调试器附加到它。

获取VS2010情况下应该不会太难,但我不知道如何调用该“附加到进程”命令。我想避免SendKeys-Type解决方案,所以我只是想知道是否有某种方法可以做到这一点?

编辑:澄清:我想使用特定的运行VS2010来调试外部应用程序。

+0

你想附加VS2010实例还是你想使用它们中的一个作为调试器? – 2010-07-16 20:12:11

+0

我也不太清楚这是否会是有益的,所以我没有张贴此作为一个完整的解决方案,但我会看在Microsoft.VisualStudio.Debugger.Interop从Visual Studio SDK http://www.microsoft.com/启动下载/ details.aspx?FAMILYID = 47305CF4-2BEA-43C0-91CD-1B853602DCC5&displaylang = EN – 2010-07-16 20:17:34

+0

@Henk我想用VS附加到一个单独的应用程序 – 2010-07-16 20:34:06

回答

6

一种方法是使用EnvDTE这是Visual Studio中的COM自动化接口:

http://msdn.microsoft.com/en-us/library/envdte(VS.100).aspx

你可以在自动化接口获取通过在运行捕鱼围绕在运行Visual Studio的实例对象表(腐烂)。一旦你有了一个接口的实例,你就可以自动选择一个Visual Studio实例来附加到你想要的过程。

下面是如何做到这一点的基本示例。您将需要向EnvDTE添加对项目的引用。该组件是在我的机器上的以下位置:

C:\ Program Files文件(x86)的\微软的Visual Studio 10.0 \ Common7 \ IDE \ PublicAssemblies \ EnvDTE.dll

更新

已更新,以提供通过进程ID获取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; 
    } 
} 
} 
+0

@迈克尔我没用过,因为VS2005这种技术,虽然我这个编码与2010年相比,并对其进行测试,您是否尝试过并提出可能有帮助的问题?我将在不久的将来在我的应用程序中引入一个功能,它依赖于这种方法,并想知道是否有2010年遇到的任何问题。谢谢。 – 2010-07-28 15:30:45

+0

要注意:如果调用脚本是从具有提升权限的进程调用的,则“TryGetVsInstance”不会返回未作为管理员启动的Visual Studio实例的DTE对象。 – 2015-07-14 10:03:42

1

蒂姆劳埃德的答案很好。这是一个小的修改,它使控制台程序将调试器附加到在命令行中指定为不区分大小写的正则表达式的程序。这非常简单,因此假定只有一个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; 
     } 
    } 
} 
相关问题