4

次のようなカスタム出力ペインを設定してVsPackageいます。

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

メッセージは、次のような方法を使用してこのペインに送信されます。

    ///--------------------------------------------------------------------------------
    /// <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);
        }
    }

external process現在のソリューションの診断結果をコンソールに送信するがあります。次のように設定されています。

///-------------------------------------------------------------------------------- 
/// <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); 
    } 
} 

external processからこれを起動するときにVSPackage、これらの結果を (間接的に) カスタム出力ペインにストリーミングし、診断ツールがレポートしているときにメッセージを表示したいと考えています。それを行う良い方法はありますか?

4

4 に答える 4

3

どうやら、Process.BeginOutputReadLine()メソッドを使用する必要があります。例はここにあります: System.Diagnostics.Process.BeginOutputReadLine

于 2011-12-01T17:53:34.580 に答える
3

主に J. Tihon の回答と the_drow の回答の一部を利用して、RunDiagnostics を更新しました。

///--------------------------------------------------------------------------------  
/// <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;
        proc.StartInfo.RedirectStandardOutput = true;
        proc.OutputDataReceived += (object sendingProcess, DataReceivedEventArgs outLine)
             => ShowOutput(String.Empty, outLine.Data, true, false);

        // execute the diagnostics  
        proc.Start();
        proc.BeginOutputReadLine();
    }  
    catch (Exception ex)  
    {  
        // put exception message in output pane  
        CustomPane.OutputString(ex.Message);  
    }  
}  
于 2011-12-01T19:26:26.087 に答える
1

リスナーを使用して、プロセスの stdout をそれにアタッチできます。

ConsoleTraceListener listener = new ConsoleTraceListener(process.StandardOutput);
Debug.Listeners.Add(listener);

プロセスが終了したら、必ず削除してください。

proc.Exited += () => Debug.Listeners.Remove(listener);

プロセスのOutputDataReceivedイベントを使用し、リスナーをアタッチする必要があります。

ConsoleTraceListener listener = new ConsoleTraceListener();
Debug.Listeners.Add(listener);

proc.OutputDataReceived += (object sendingProcess, DataReceivedEventArgs outLine) => Trace.WriteLine(outLine.Data);

プロセスが終了したら、必ず削除してください。

proc.Exited += (object sender, EventArgs e) => Debug.Listeners.Remove(listener);
于 2011-12-01T17:39:05.840 に答える
1

OutPutDataReceived+BeginOutputReadLine はよりエレガントでシンプルなソリューションのように見えますが、別の方法を紹介します。BackgroundWorkerと、 hereからインスピレーションを得た ProcessOutPutHandler で問題を解決しました。このアプローチでは、stdout と stderr からのメッセージも個別に処理され、出力に応じて BackgroundWorker に進行状況を報告できます。ここでは、出力に標準の VS 出力ウィンドウを使用しますが、OutputPane でも同様に機能するはずです。

public class ProcessOutputHandler
{
    public Process proc { get; set; }
    public string StdOut { get; set; }
    public string StdErr { get; set; }
    private IVsOutputWindowPane _pane;
    private BackgroundWorker _worker;

    /// <summary>  
    /// The constructor requires a reference to the process that will be read.  
    /// The process should have .RedirectStandardOutput and .RedirectStandardError set to true.  
    /// </summary>  
    /// <param name="process">The process that will have its output read by this class.</param>  
    public ProcessOutputHandler(Process process, BackgroundWorker worker)
    {
        _worker = worker;
        proc = process;
        IVsOutputWindow outputWindow =
        Package.GetGlobalService(typeof(SVsOutputWindow)) as IVsOutputWindow;

        Guid guidGeneral = Microsoft.VisualStudio.VSConstants.OutputWindowPaneGuid.GeneralPane_guid;
        int hr = outputWindow.CreatePane(guidGeneral, "Phone Visualizer", 1, 0);
        hr = outputWindow.GetPane(guidGeneral, out _pane);
        _pane.Activate();
        _pane.OutputString("Starting Ui State workers..");

        StdErr = "";
        StdOut = "";
        Debug.Assert(proc.StartInfo.RedirectStandardError, "RedirectStandardError must be true to use ProcessOutputHandler.");
        Debug.Assert(proc.StartInfo.RedirectStandardOutput, "RedirectStandardOut must be true to use ProcessOutputHandler.");
    }

    /// <summary>  
    /// This method starts reading the standard error stream from Process.  
    /// </summary>  
    public void ReadStdErr()
    {
        string line;
        while ((!proc.HasExited) && ((line = proc.StandardError.ReadLine()) != null))
        {
            StdErr += line;
            _pane.OutputString(line + "\n");
            // Here I could do something special if errors occur
        }
    }
    /// <summary>  
    /// This method starts reading the standard output sream from Process.  
    /// </summary>  
    public void ReadStdOut()
    {
        string line;
        while ((!proc.HasExited) && ((line = proc.StandardOutput.ReadLine()) != null))
        {
            StdOut += line;
            _pane.OutputString(line + "\n");
            if (_worker != null && line.Contains("Something I'm looking for"))
            {                            
               _worker.ReportProgress(20, "Something worth mentioning happened");
            }
        }
    }

}

そして使用法:

void RunProcess(string fileName, string arguments, BackgroundWorker worker)
{
  // prep process
  ProcessStartInfo psi = new ProcessStartInfo(fileName, arguments);
  psi.UseShellExecute = false;
  psi.RedirectStandardOutput = true;
  psi.RedirectStandardError = true;
  // start process
  using (Process process = new Process())
  {
    // pass process data
    process.StartInfo = psi;
    // prep for multithreaded logging
    ProcessOutputHandler outputHandler = new ProcessOutputHandler(process,worker);
    Thread stdOutReader = new Thread(new ThreadStart(outputHandler.ReadStdOut));
    Thread stdErrReader = new Thread(new ThreadStart(outputHandler.ReadStdErr));
    // start process and stream readers
    process.Start();
    stdOutReader.Start();
    stdErrReader.Start();
    // wait for process to complete
    process.WaitForExit();
   }
}

これは BackgroundWorkerDoWorkメソッドから呼び出され、Worker が参照として渡されます。

于 2011-12-02T08:16:36.573 に答える