Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a good way to stream the results from an external process into a Visual Studio output pane?

I have a custom output pane set up in a VsPackage similar to the following:

    ///--------------------------------------------------------------------------------
    /// <summary>This property gets the custom output pane.</summary>
    ///--------------------------------------------------------------------------------
    private Guid _customPaneGuid = Guid.Empty;
    private IVsOutputWindowPane _customPane = null;
    private IVsOutputWindowPane customPane
    {
        get
        {
            if (_customPane == null)
            {
                IVsOutputWindow outputWindow = GetService(typeof(SVsOutputWindow)) as IVsOutputWindow;
                if (outputWindow != null)
                {
                    // look for existing solution updater pane
                    if (_customPaneGuid == Guid.Empty || ErrorHandler.Failed(outputWindow.GetPane(ref _customPaneGuid, out _customPane)) || _customPane == null)
                    {
                        // create a new solution updater pane
                        outputWindow.CreatePane(ref _customPaneGuid, "My Output", 1, 1);
                        if (ErrorHandler.Failed(outputWindow.GetPane(ref _customPaneGuid, out _customPane)) || _customPane == null)
                        {
                            // pane could not be created and retrieved, throw exception
                            throw new Exception("Custom pane could not be created and/or retrieved");
                        }
                    }
                }
            }
            if (_customPane != null)
            {
                _customPane.Activate();
            }
            return _customPane;
        }
    }

And messages are sent to this pane using a method similar to:

    ///--------------------------------------------------------------------------------
    /// <summary>This method displays a message in the output area.</summary>
    /// 
    /// <param name="outputTitle">The title for the message.</param>
    /// <param name="outputMessage">The message to show.</param>
    /// <param name="appendMessage">Flag indicating whether message should be appended to existing message.</param>
    ///--------------------------------------------------------------------------------
    public void ShowOutput(string outputTitle, string outputMessage, bool appendMessage, bool isException)
    {
        if (appendMessage == false)
        {
            // clear output pane
            CustomPane.Clear();
        }

        if (outputTitle != string.Empty)
        {
            // put output title to output pane
            CustomPane.OutputString("\r\n" + outputTitle);
        }

        // put output message to output pane
        CustomPane.OutputString("\r\n" + outputMessage);

        if (isException == true)
        {
            // show message box
            MessageBox.Show(outputTitle + "\r\n" + outputMessage, outputTitle);
        }
    }

I have an external process that sends diagnostic results of the current solution to the console. It is set up similar to the following:

///-------------------------------------------------------------------------------- 
/// <summary>This method handles clicking on the Run Diagnostics 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 RunDiagnostics_Click(object inputCommandBarControl, ref bool handled, ref bool cancelDefault) 
{ 
    try 
    { 
        // set up and execute diagnostics thread 
        RunDiagnosticsDelegate RunDiagnosticsDelegate = RunDiagnostics; 
        RunDiagnosticsDelegate.BeginInvoke(RunDiagnosticsCompleted, RunDiagnosticsDelegate); 
    } 
    catch (Exception ex) 
    { 
        // put exception message in output pane 
        CustomPane.OutputString(ex.Message); 
    } 
} 

protected delegate void RunDiagnosticsDelegate(); 

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

        // execute the diagnostics 
        proc.Start(); 

        // put diagnostics output to output pane 
        CustomPane.OutputString(proc.StandardOutput.ReadToEnd()); 
        CustomPane.OutputString("Diagnostics run complete."); 
    } 
    catch (Exception ex) 
    { 
        // put exception message in output pane 
        CustomPane.OutputString(ex.Message); 
    } 
} 

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

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

        RunDiagnosticsDelegate.EndInvoke(ar); 
    } 
    catch (Exception ex) 
    { 
        // put exception message in output pane 
        CustomPane.OutputString(ex.Message); 
    } 
} 

When I launch this external process from the VSPackage, I would like to stream these results (indirectly) to the custom output pane, showing messages as the diagnostics tool is reporting them. Is there a good way to do that?

like image 450
Dave Clemmer Avatar asked Feb 22 '23 06:02

Dave Clemmer


1 Answers

Apparently you have to use the Process.BeginOutputReadLine() method. An example can be found here: System.Diagnostics.Process.BeginOutputReadLine.

like image 178
J. Tihon Avatar answered Apr 28 '23 13:04

J. Tihon