2010-01-13 47 views
21

我有一些工具可以在.NET解決方案上執行更新,但他們需要知道解決方案所在的目錄。以編程方式從插件中獲取當前的Visual Studio IDE解決方案目錄

我將這些工具添加爲外部工具,它們出現在IDE Tools菜單中,並提供$(SolutionDir)作爲參數。這工作正常。但是,我希望這些工具能夠通過自定義頂級菜單(爲其創建Visual Studio集成包項目)和解決方案節點上的上下文菜單(爲此我創建了一個Visual Studio加載項目)。我正在尋找通過這些上下文獲取當前解決方案目錄的方法。

我試圖從VisualStudio.DTE對象獲取解決方案的信息:

EnvDTE.DTE dte = (EnvDTE.DTE)System.Runtime.InteropServices.Marshal.GetActiveObject("VisualStudio.DTE"); 
string solutionDir = System.IO.Path.GetDirectoryName(dte.Solution.FullName); 

但是,這將返回解決方案目錄的加載項,而不是當前的解決方案。

我試圖呼應$(SolutionDir)和回讀:

System.Diagnostics.ProcessStartInfo procStartInfo = new System.Diagnostics.ProcessStartInfo("cmd", "echo $(SolutionDir)"); 

// The following commands are needed to redirect the standard output. 
// This means that it will be redirected to the Process.StandardOutput StreamReader. 
procStartInfo.RedirectStandardOutput = true; 
procStartInfo.UseShellExecute = false; 
// Do not create the black window. 
procStartInfo.CreateNoWindow = true; 
// Now we create a process, assign its ProcessStartInfo and start it 
System.Diagnostics.Process proc = new System.Diagnostics.Process(); 
proc.StartInfo = procStartInfo; 
proc.Start(); 
// Get the output into a string 
string result = proc.StandardOutput.ReadToEnd(); 

不過,這回的目錄的IDE,而不是當前的解決方案。

我在解決方案節點CommandBar中沒有看到任何相關信息。

或者,如果有方法以編程方式訪問已定義的Visual Studio外部工具並啓動它們(使用已定義的宏參數),那就行了。

解決方案是什麼?

+0

2+再次顯然我在這裏跟蹤你有了這個DTE瘋狂笑 – Terrance 2010-12-02 22:04:16

回答

18

EnvDTE.DTE DTE = (EnvDTE.DTE)System.Runtime.InteropServices.Marshal.GetActiveObject( 「VisualStudio.DTE」); string solutionDir = System.IO.Path.GetDirectoryName(dte.Solution.FullName);

但是,這會返回解決方案 目錄中的加入項,而不是當前的解決方案 。

你的方法來獲取目錄是好的。有什麼不對的是你得到VisualStudio.DTE對象的方式。這段代碼叫什麼名字?我假設它在你的加載項中。您是否在Visual Studio中執行(調試)加載項?這會打開您打開解決方案的另一個Visual Studio實例?所以你有兩個Visual Studio實例。

GetActiveObject("VisualStudio.DTE")得到一個隨機的Visual Studio實例。在你的情況下,顯然Visual Studio帶有一個附加項目,因爲你獲得了加載項的路徑。這是解釋什麼是你的問題的原因。

獲得DTE的正確方法非常簡單。事實上,你的加載項已經引用了它運行的DTE(也就是解決方案在其中打開)。它存儲在加載項connect類的全局變量_applicationObject中。當您的加載項在OnConnection事件處理程序中啓動時設置。因此,所有你需要的是撥打:

string solutionDir = System.IO.Path.GetDirectoryName(_applicationObject.Solution.FullName); 
+0

感謝彼得,這恰恰是問題和解決方案!現在,我將尋找一種方法,通過自定義菜單執行工具來輸出輸出到輸出窗口,而不是單獨的窗口,所有這些都將完美工作。再次感謝。 – 2010-01-13 18:53:08

6

隨着彼得在正確的方向推,我設置的上下文菜單插件推出與解決方案目錄的外部工具,並將結果輸出到輸出窗格。從加入一些例子導語:

///-------------------------------------------------------------------------------- 
    /// <summary>This method implements the OnConnection method of the IDTExtensibility2 interface. Receives notification that the Add-in is being loaded.</summary> 
    /// 
    /// <param term='application'>Root object of the host application.</param> 
    /// <param term='connectMode'>Describes how the Add-in is being loaded.</param> 
    /// <param term='addInInst'>Object representing this Add-in.</param> 
    /// <seealso class='IDTExtensibility2' /> 
    ///-------------------------------------------------------------------------------- 
    public void OnConnection(object application, ext_ConnectMode connectMode, object addInInst, ref Array custom) 
    { 
     _applicationObject = (DTE2)application; 
     _addInInstance = (AddIn)addInInst; 

     // Get the solution command bar 
     CommandBar solutionCommandBar = ((CommandBars)_applicationObject.CommandBars)["Solution"]; 

     // Set up the main InCode 
     CommandBarPopup solutionPopup = (CommandBarPopup)solutionCommandBar.Controls.Add(MsoControlType.msoControlPopup, System.Reflection.Missing.Value, System.Reflection.Missing.Value, 1, true); 
     solutionPopup.Caption = "InCode"; 

     // Add solution updater submenu 
     CommandBarControl solutionUpdaterControl = solutionPopup.Controls.Add(MsoControlType.msoControlButton, System.Reflection.Missing.Value, System.Reflection.Missing.Value, 1, true); 
     solutionUpdaterControl.Caption = "Update Solution"; 
     updateSolutionMenuItemHandler = (CommandBarEvents)_applicationObject.Events.get_CommandBarEvents(solutionUpdaterControl); 
     updateSolutionMenuItemHandler.Click += new _dispCommandBarControlEvents_ClickEventHandler(updateSolution_Click); 
    } 

    // The event handlers for the solution submenu items 
    CommandBarEvents updateSolutionMenuItemHandler; 

    ///-------------------------------------------------------------------------------- 
    /// <summary>This property gets the solution updater output pane.</summary> 
    ///-------------------------------------------------------------------------------- 
    protected OutputWindowPane _solutionUpdaterPane = null; 
    protected OutputWindowPane SolutionUpdaterPane 
    { 
     get 
     { 
      if (_solutionUpdaterPane == null) 
      { 
       OutputWindow outputWindow = _applicationObject.ToolWindows.OutputWindow; 
       foreach (OutputWindowPane loopPane in outputWindow.OutputWindowPanes) 
       { 
        if (loopPane.Name == "Solution Updater") 
        { 
         _solutionUpdaterPane = loopPane; 
         return _solutionUpdaterPane; 
        } 
       } 
       _solutionUpdaterPane = outputWindow.OutputWindowPanes.Add("Solution Updater"); 
      } 
      return _solutionUpdaterPane; 
     } 
    } 

    ///-------------------------------------------------------------------------------- 
    /// <summary>This method handles clicking on the Update Solution submenu.</summary> 
    /// 
    /// <param term='inputCommandBarControl'>The control that is source of the click.</param> 
    /// <param term='handled'>Handled flag.</param> 
    /// <param term='cancelDefault'>Cancel default flag.</param> 
    ///-------------------------------------------------------------------------------- 
    protected void updateSolution_Click(object inputCommandBarControl, ref bool handled, ref bool cancelDefault) 
    { 
     try 
     { 
      // set up and execute solution updater thread 
      UpdateSolutionDelegate updateSolutionDelegate = UpdateSolution; 
      updateSolutionDelegate.BeginInvoke(UpdateSolutionCompleted, updateSolutionDelegate); 
     } 
     catch (System.Exception ex) 
     { 
      // put exception message in output pane 
      SolutionUpdaterPane.OutputString(ex.Message); 
     } 
    } 

    protected delegate void UpdateSolutionDelegate(); 

    ///-------------------------------------------------------------------------------- 
    /// <summary>This method launches the solution updater to update the solution.</summary> 
    ///-------------------------------------------------------------------------------- 
    protected void UpdateSolution() 
    { 
     try 
     { 
      // set up solution updater process 
      string solutionDir = System.IO.Path.GetDirectoryName(_applicationObject.Solution.FullName); 
      System.Diagnostics.ProcessStartInfo procStartInfo = new System.Diagnostics.ProcessStartInfo(@"SolutionUpdater.exe", solutionDir); 
      procStartInfo.RedirectStandardOutput = true; 
      procStartInfo.UseShellExecute = false; 
      procStartInfo.CreateNoWindow = true; 
      System.Diagnostics.Process proc = new System.Diagnostics.Process(); 
      proc.StartInfo = procStartInfo; 

      // execute the solution updater 
      proc.Start(); 

      // put solution updater output to output pane 
      SolutionUpdaterPane.OutputString(proc.StandardOutput.ReadToEnd()); 
      SolutionUpdaterPane.OutputString("Solution update complete."); 
     } 
     catch (System.Exception ex) 
     { 
      // put exception message in output pane 
      SolutionUpdaterPane.OutputString(ex.Message); 
     } 
    } 

    ///-------------------------------------------------------------------------------- 
    /// <summary>This method completing the update solution thread.</summary> 
    /// 
    /// <param name="ar">IAsyncResult.</param> 
    ///-------------------------------------------------------------------------------- 
    protected void UpdateSolutionCompleted(IAsyncResult ar) 
    { 
     try 
     { 
      if (ar == null) throw new ArgumentNullException("ar"); 

      UpdateSolutionDelegate updateSolutionDelegate = ar.AsyncState as UpdateSolutionDelegate; 
      Trace.Assert(updateSolutionDelegate != null, "Invalid object type"); 

      updateSolutionDelegate.EndInvoke(ar); 
     } 
     catch (System.Exception ex) 
     { 
      // put exception message in output pane 
      SolutionUpdaterPane.OutputString(ex.Message); 
     } 
    } 
+0

不,沒有找到一種輪詢外部過程的方法,我最終做了我需要的作爲VS包中的內部過程。 – 2011-10-28 15:14:53

+0

我有一個結果輪詢的解決方案(或者將輸出流式傳輸到輸出窗格),至少在使用VSPackage時是如此。而不是這個問題的範圍(並不適合在這裏),所以也許你可以開一個新的問題,我會在那裏回答。 – 2011-12-01 11:50:48

+0

好吧,我爲此拋出了一個單獨的問題,如果您的答案看起來不錯,我會接受! http://stackoverflow.com/questions/8345636/is-there-a-good-way-to-stream-the-results-from-an-external-process-into-a-visual – 2011-12-01 17:30:35

相關問題