2010-01-13 17 views
21

Certains outils effectuent des mises à jour sur les solutions .NET, mais ils doivent connaître le répertoire dans lequel se trouve la solution.Récupération par programme du répertoire de la solution IDE Visual Studio en cours à partir des add-ons

J'ai ajouté ces outils en tant qu'outils externes, où ils apparaissent dans le menu Outils IDE, et en fournissant $(SolutionDir) comme argument. Cela fonctionne bien. Cependant, je souhaite que ces outils soient plus facilement accessibles dans l'EDI pour l'utilisateur via un menu de niveau supérieur personnalisé (pour lequel j'ai créé un projet de package d'intégration Visual Studio) et un menu contextuel sur les nœuds de solution (pour lesquels J'ai créé un projet complémentaire Visual Studio). Je suis à la recherche d'un moyen d'obtenir le répertoire de solution actuel à travers ces contextes.

J'ai essayé d'obtenir les informations de la solution de l'objet VisualStudio.DTE:

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

Mais, cela renvoie le répertoire de solution pour les ins add, pas la solution actuelle.

J'ai essayé écho $(SolutionDir) et en les lisant:

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

Mais, ce retour dans le répertoire de l'IDE, pas la solution actuelle.

Je n'ai vu aucune information pertinente dans le nœud de solution CommandBar.

Sinon, s'il existait un moyen d'accéder par programme aux outils externes Visual Studio définis et de les lancer (en utilisant les arguments de macro déjà définis), cela fonctionnerait.

Quelle est la solution?

+0

2+ nouveau apparemment je suis ici avec vous stalking cette folie DTE lol – Terrance

Répondre

18

EnvDTE.DTE dte = (EnvDTE.DTE) System.Runtime.InteropServices.Marshal.GetActiveObject ("VisualStudio.DTE"); chaîne solutionDir = System.IO.Path.GetDirectoryName (dte.Solution.FullName); Mais, cela renvoie le répertoire de la solution pour l'insertion, pas la solution actuelle .

Votre approche pour obtenir le répertoire est bonne. Quel est le problème est la façon dont vous obtenez l'objet VisualStudio.DTE. Où est appelé ce code? Je suppose que c'est dans votre add-in. Exécutez-vous (debug) votre complément dans Visual Studio qui ouvre une autre instance de Visual Studio où vous ouvrez votre solution? Vous avez donc deux instances de Visual Studio. Le GetActiveObject("VisualStudio.DTE") obtient une instance Visual Studio aléatoire. Dans votre cas, il s'agit apparemment de Visual Studio avec un projet complémentaire puisque vous obtenez le chemin vers votre complément. C'est pour expliquer quelle serait la raison de votre problème.

La façon correcte d'obtenir DTE est très simple. En fait, votre complément a déjà une référence à DTE dans lequel il s'exécute (c'est-à-dire dans lequel la solution est ouverte). Il est stocké dans une variable globale _applicationObject dans votre classe de connexion add-in. Il est défini lorsque votre complément commence dans le gestionnaire d'événements OnConnection.Donc, tout ce dont vous avez besoin est d'appeler:

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

Merci Peter, qui était précisément la question et la solution! Maintenant, je vais chercher un moyen d'obtenir la sortie de l'exécution des outils via les menus personnalisés pour aller à la fenêtre de sortie au lieu d'une fenêtre séparée et tout ira parfaitement. Merci encore. –

6

Avec la poussée de Peter dans la bonne direction, je mis en place dans le menu contextuel Addin pour lancer un outil externe avec le répertoire de solution, et la sortie des résultats à la sous-fenêtre de sortie. Quelques exemples texte de présentation de l'ajouter dans:

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

Non, je n'ai pas trouvé un moyen d'interroger un processus externe, j'ai fini par faire ce dont j'avais besoin en tant que processus interne dans un paquet VS. –

+0

J'ai une solution pour l'interrogation des résultats (ou plutôt stream la sortie dans le volet de sortie), au moins lors de l'utilisation d'un VSPackage. Plutôt hors de portée pour cette question (et ne correspondra pas ici ..), alors peut-être que vous pouvez ouvrir une nouvelle question et je vais y répondre. –

+0

OK, j'ai jeté ensemble une question distincte pour cela, si votre réponse semble bonne, je vais accepter! http://stackoverflow.com/questions/8345636/is-there-a-good-way-to-stream-the-results-from-an-external-process-into-a-visual –