2010-01-13 18 views
21

Ich habe einige Tools, die Updates für .NET-Lösungen durchführen, aber sie müssen das Verzeichnis kennen, in dem sich die Lösung befindet.Programmgesteuertes Abrufen des aktuellen Visual Studio IDE-Lösungsverzeichnisses aus Addins

Ich habe diese Tools als externe Tools hinzugefügt, wo sie im IDE-Tools-Menü erscheinen und $(SolutionDir) als Argument liefern. Das funktioniert gut.

Ich möchte jedoch, dass diese Tools in der IDE für den Benutzer über ein benutzerdefiniertes Top-Level-Menü (für das ich ein Visual Studio-Integrationspaket-Projekt erstellte) und über ein Kontextmenü auf Lösung Knoten (für die Ich habe ein Visual Studio-Add-In-Projekt erstellt). Ich suche nach einer Möglichkeit, das aktuelle Lösungsverzeichnis durch diese Kontexte zu bekommen.

Ich habe versucht, die Lösung Informationen aus dem VisualStudio.DTE Objekt erhalten:

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

Aber dies gibt die Lösung Verzeichnis für die Add-In, nicht die aktuellen Lösung.

Ich versuchte Echo $(SolutionDir) und lesen es zurück:

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(); 

Aber dies das Verzeichnis für die IDE zurückgegeben, nicht die aktuelle Lösung.

Ich habe keine relevanten Informationen in der Lösung Knoten CommandBar.

Wenn es eine Möglichkeit gab, programmgesteuert auf die definierten externen Tools von Visual Studio zuzugreifen und diese zu starten (mit den bereits definierten Makroargumenten), würde das funktionieren.

Was ist die Lösung?

+0

2+ wieder scheinbar ich Stalking Sie hier Mit diesem DTE Wahnsinn lol – Terrance

Antwort

18

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

Aber das gibt die Lösung Verzeichnis für die Add-Ins, nicht die aktuelle Lösung zurück.

Ihr Ansatz, um das Verzeichnis zu bekommen, ist gut. Was ist falsch ist die Art, wie Sie das Objekt VisualStudio.DTE bekommen. Wo wird dieser Code aufgerufen? Ich nehme an, dass es in Ihrem Add-In ist. Führen Sie Ihr Add-In in Visual Studio aus, das eine andere Visual Studio-Instanz öffnet, in der Sie Ihre Lösung öffnen? Sie haben also zwei Instanzen von Visual Studio.

Die GetActiveObject("VisualStudio.DTE") ruft eine zufällige Visual Studio-Instanz ab. In Ihrem Fall handelt es sich offensichtlich um Visual Studio mit einem Add-In-Projekt, da Sie den Pfad zu Ihrem Add-In erhalten. Das ist zur Erklärung, was der Grund Ihres Problems sein würde.

Der richtige Weg, DTE zu bekommen, ist sehr einfach. Tatsächlich hat Ihr Add-In bereits Bezug auf DTE, in dem es ausgeführt wird (dh in dem die Lösung geöffnet ist). Es wird in einer globalen Variablen _applicationObject in Ihrer add-in connect-Klasse gespeichert. Es wird festgelegt, wenn Ihr Add-In in dem OnConnection-Ereignishandler gestartet wird.Also alles, was Sie brauchen, ist zu nennen:

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

Danke Peter, das war genau das Problem und Lösung! Jetzt werde ich nach einem Weg suchen, die Ausgabe von der Ausführung der Werkzeuge über die benutzerdefinierten Menüs zu erhalten, um zum Ausgabefenster statt eines separaten Fensters zu gelangen, und alles wird perfekt funktionieren. Danke noch einmal. –

6

Mit Peter Schubs in die richtige Richtung, ich das Kontextmenü Addin einrichten ein externes Tool mit der Lösung Verzeichnis zu starten, und geben die Ergebnisse an den Ausgangsbereich. Einige Beispiele Klappentext aus dem Add in:

///-------------------------------------------------------------------------------- 
    /// <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

Nein, ich habe keine Möglichkeit gefunden, einen externen Prozess abzufragen, ich habe letztendlich getan, was ich als internen Prozess in einem VS-Paket brauchte. –

+0

Ich habe eine Lösung für die Ergebnisabfrage (oder eher streamen Sie die Ausgabe in den Ausgabebereich), zumindest bei Verwendung eines VSPackage. Für diese Frage eher aus dem Rahmen (und passen nicht hier ..), so können Sie vielleicht eine neue Frage eröffnen und ich werde dort antworten. –

+0

OK, ich habe dafür eine separate Frage zusammengestellt, wenn deine Antwort gut aussieht, nehme ich an! http://stackoverflow.com/questions/8345636/is-there-a-good-way-to-stream-the-results-from-an-external-process-into-a-a-visual –