2010-07-16 110 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; 
     } 
    } 
} 
相關問題