2010-01-13 18 views
21

Tengo algunas herramientas que realizan actualizaciones en soluciones .NET, pero necesitan saber el directorio donde se encuentra la solución.Programando obtener el directorio actual de la solución IDE de Visual Studio desde complementos

Agregué estas herramientas como Herramientas Externas, donde aparecen en el menú Herramientas IDE, y suministrando $(SolutionDir) como argumento. Esto funciona bien

Sin embargo, quiero que estas herramientas sean más fáciles de acceder en el IDE para el usuario a través de un menú personalizado de nivel superior (para el cual creé un proyecto de paquete de integración Visual Studio) y un menú contextual en nodos de solución (para los cuales Creé un proyecto de complemento de Visual Studio). Estoy buscando una manera de obtener el directorio de soluciones actual a través de estos contextos.

He intentado obtener la información solución del objeto VisualStudio.DTE:

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

embargo, este resultado el directorio solución para las ins agregar, no la solución actual.

me trataron eco $(SolutionDir) y leer de nuevo:

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

Pero, esto devolverá el directorio para el IDE, no la solución actual.

No vi ninguna información relevante en el nodo de solución CommandBar.

Alternativamente, si hubiera una forma de acceder mediante programación a las herramientas externas de Visual Studio definidas y ejecutarlas (utilizando los argumentos de macro ya definidos), eso funcionaría.

¿Cuál es la solución?

+0

2+ nuevo parecer que estoy acechando aquí con esta locura DTE lol – Terrance

Respuesta

18

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

Pero, esto devuelve el directorio de la solución para los complementos, no la solución actual .

Su enfoque para obtener el directorio es bueno. Lo que está mal es la forma en que obtienes el objeto VisualStudio.DTE. ¿Dónde se llama este código? Supongo que está en tu complemento. ¿Ejecuta (depura) su complemento en Visual Studio que abre otra instancia de Visual Studio donde abre su solución? Entonces tienes dos instancias de Visual Studio.

El GetActiveObject("VisualStudio.DTE") obtiene una instancia aleatoria de Visual Studio. En su caso, es aparentemente Visual Studio con un proyecto adicional ya que obtiene la ruta a su complemento. Es por una explicación cuál sería el motivo de su problema.

La forma correcta de obtener DTE es muy simple. De hecho, su complemento ya tiene una referencia al DTE en el que se ejecuta (es decir, en el que se abre la solución). Se almacena en una variable global _applicationObject en su clase de conexión de complemento. Se establece cuando el complemento se inicia en el controlador de eventos OnConnection.Así que todo lo que necesita es llamar:

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

Gracias Peter, que era precisamente el problema y la solución! Ahora buscaré la manera de hacer que la salida ejecute las herramientas a través de los menús personalizados para ir a la ventana de salida en lugar de a una ventana separada y todo funcionará perfectamente. Gracias de nuevo. –

6

Con el empuje de Pedro en la dirección correcta, puedo configurar el complemento menú contextual para lanzar una herramienta externa con el directorio de la solución, y la salida de los resultados al panel de salida. Algunos ejemplos de propaganda en el complemento:

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

No, no encontré una manera de sondear un proceso externo, terminé haciendo lo que necesitaba como un proceso interno en un paquete de VS. –

+0

Tengo una solución para el sondeo de resultados (o más bien transmitir la salida en el panel de salida), al menos cuando se utiliza un VSPackage. Más bien fuera del alcance de esta pregunta (y no encajará aquí ...), entonces quizás pueda abrir una nueva pregunta y responderé allí. –

+0

OK, hice una pregunta separada para esto, si tu respuesta se ve bien, ¡aceptaré! http://stackoverflow.com/questions/8345636/is-there-a-good-way-to-stream-the-results-from-an-external-process-into-a-visual –

Cuestiones relacionadas