c # запустить CL EXE-файл или пакетного вывода CIVE LIVE в текстовое поле? - PullRequest
5 голосов
/ 06 мая 2010

Можно ли запустить любую программу или командный файл на основе командной строки и захватить (перенаправить) вывод в текстовое поле LIVE

CL требует времени и выдает текст!

что-то вроде tracert.exe (это занимает много времени и выдает много текста).

на самом деле я буду работать с tracert.exe, и мне нравится захватывать вывод в реальном времени и показывать его в текстовом поле во время его работы

EDIT: Моя проблема состоит в том, чтобы иметь его в прямом эфире Я имею в виду, что любая новая строка или символ, производимый консолью, будет отправляться / вытягиваться в / посредством textBox НЕ, пока программа не будет завершена!

Просто я хочу построить именно так http://www.codeproject.com/KB/threads/redir.aspx (посмотрите демо), но в C #

вот мой код:

private void button1_Click(object sender, EventArgs e)
{    
     Process pc = new Process();
     pc.StartInfo.FileName = "tracert.exe";
     pc.StartInfo.Arguments = "google.com";
     pc.StartInfo.UseShellExecute = false;
     pc.StartInfo.RedirectStandardOutput = true;
     pc.StartInfo.CreateNoWindow = true;
     pc.Start();

     richTextBox1.Text = pc.StandardOutput.ReadToEnd();

     pc.WaitForExit();    
}

EDIT

с вашей помощью (большое спасибо, ребята) и по этой ссылке: http://msdn.microsoft.com/query/dev10.query?appId=Dev10IDEF1&l=EN-US&k=k%28EHINVALIDOPERATION.WINFORMS.ILLEGALCROSSTHREADCALL%29;k%28TargetFrameworkMoniker-%22.NETFRAMEWORK%2cVERSION%3dV2.0%22%29;k%28DevLang-CSHARP%29&rd=true

Я решаю это с помощью этого кода (как вы думаете, это нормально?):

namespace GUIforCL2
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        Process _cmd;

        delegate void SetTextCallback(string text);

        private void SetText(string text)
        {
            if (this.richTextBox1.InvokeRequired)
            {
                SetTextCallback d = new SetTextCallback(SetText);
                this.Invoke(d, new object[] { text });
            }
            else
            {
                this.richTextBox1.Text += text + Environment.NewLine;
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            ProcessStartInfo cmdStartInfo = new ProcessStartInfo("tracert.exe");
            cmdStartInfo.Arguments = "google.com";
            cmdStartInfo.CreateNoWindow = true;
            cmdStartInfo.RedirectStandardInput = true;
            cmdStartInfo.RedirectStandardOutput = true;
            cmdStartInfo.RedirectStandardError = true;
            cmdStartInfo.UseShellExecute = false;
            cmdStartInfo.WindowStyle = ProcessWindowStyle.Hidden;

            _cmd = new Process();
            _cmd.StartInfo = cmdStartInfo;

            if (_cmd.Start())
            {
                _cmd.OutputDataReceived += new DataReceivedEventHandler(_cmd_OutputDataReceived);
                _cmd.ErrorDataReceived += new DataReceivedEventHandler(_cmd_ErrorDataReceived);
                _cmd.Exited += new EventHandler(_cmd_Exited);

                _cmd.BeginOutputReadLine();
                _cmd.BeginErrorReadLine();
            }
            else
            {
                _cmd = null;
            }
        }

        void _cmd_OutputDataReceived(object sender, DataReceivedEventArgs e)
        {
            UpdateConsole(e.Data);
        }

        void _cmd_ErrorDataReceived(object sender, DataReceivedEventArgs e)
        {
            UpdateConsole(e.Data, Brushes.Red);
        }

        void _cmd_Exited(object sender, EventArgs e)
        {
            _cmd.OutputDataReceived -= new DataReceivedEventHandler(_cmd_OutputDataReceived);
            _cmd.Exited -= new EventHandler(_cmd_Exited);
        }

        private void UpdateConsole(string text)
        {
            UpdateConsole(text, null);
        }
        private void UpdateConsole(string text, Brush color)
        {
            WriteLine(text, color);
        }

        private void WriteLine(string text, Brush color)
        {
            if (text != null)
            {    
                SetText(text);
            }
        }
    }
}

Ответы [ 2 ]

4 голосов
/ 06 мая 2010

Когда вы создаете экземпляр Process для tracert, вам необходимо установить ProcessStartInfo.UseShellExecute на false и ProcessStartInfo.RedirectStandardOutput на true. Это позволит вам использовать свойство Process.StandardOutput для чтения вывода.

Вы можете использовать Process.BeginOutputReadLine, чтобы запустить асинхронное чтение и добавить обработчик событий в Process.OutputDataReceived.

Обновление: Вот пример программы WPF, которая делает то, что вы хотите.

MainWindow.xaml:

<Window x:Class="Console.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525" Loaded="Window_Loaded" Closed="Window_Closed">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <ScrollViewer Name="outputViewer" SizeChanged="ScrollViewer_SizeChanged" >
            <TextBlock Name="output" />
        </ScrollViewer>
        <TextBox Grid.Row="1" Name="input" KeyDown="input_KeyDown" />
    </Grid>
</Window>

MainWindow.cs:

using System;
using System.Diagnostics;
using System.Windows;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;

namespace Console
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            ProcessStartInfo cmdStartInfo = new ProcessStartInfo("cmd.exe");
            cmdStartInfo.CreateNoWindow = true;
            cmdStartInfo.RedirectStandardInput = true;
            cmdStartInfo.RedirectStandardOutput = true;
            cmdStartInfo.RedirectStandardError = true;
            cmdStartInfo.UseShellExecute = false;
            cmdStartInfo.WindowStyle = ProcessWindowStyle.Hidden;

            _cmd = new Process();
            _cmd.StartInfo = cmdStartInfo;

            if (_cmd.Start() == true)
            {
                _cmd.OutputDataReceived += new DataReceivedEventHandler(_cmd_OutputDataReceived);
                _cmd.ErrorDataReceived += new DataReceivedEventHandler(_cmd_ErrorDataReceived);
                _cmd.Exited += new EventHandler(_cmd_Exited);

                _cmd.BeginOutputReadLine();
                _cmd.BeginErrorReadLine();
            }
            else
            {
                _cmd = null;
            }
        }

        private void Window_Closed(object sender, EventArgs e)
        {
            if ((_cmd != null) &&
                (_cmd.HasExited != true))
            {
                _cmd.CancelErrorRead();
                _cmd.CancelOutputRead();
                _cmd.Close();
                _cmd.WaitForExit();
            }
        }

        void _cmd_OutputDataReceived(object sender, DataReceivedEventArgs e)
        {
            UpdateConsole(e.Data);
        }

        void _cmd_ErrorDataReceived(object sender, DataReceivedEventArgs e)
        {
            UpdateConsole(e.Data, Brushes.Red);
        }

        void _cmd_Exited(object sender, EventArgs e)
        {
            _cmd.OutputDataReceived -= new DataReceivedEventHandler(_cmd_OutputDataReceived);
            _cmd.Exited -= new EventHandler(_cmd_Exited);
        }

        private void ScrollViewer_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            outputViewer.ScrollToBottom();
        }

        private void input_KeyDown(object sender, KeyEventArgs e)
        {
            switch (e.Key)
            {
                case Key.Enter:
                    _cmd.StandardInput.WriteLine(input.Text);
                    input.Text = "";
                    break;
                case Key.Escape:
                    input.Text = "";
                    break;
            }
        }

        private void UpdateConsole(string text)
        {
            UpdateConsole(text, null);
        }

        private void UpdateConsole(string text, Brush color)
        {
            if (!output.Dispatcher.CheckAccess())
            {
                output.Dispatcher.Invoke(
                        new Action(
                                () =>
                                {
                                    WriteLine(text, color);
                                }
                            )
                    );
            }
            else
            {
                WriteLine(text, color);
            }
        }

        private void WriteLine(string text, Brush color)
        {
            if (text != null)
            {
                Span line = new Span();
                if (color != null)
                {
                    line.Foreground = color;
                }
                foreach (string textLine in text.Split(Environment.NewLine.ToCharArray(), StringSplitOptions.RemoveEmptyEntries))
                {
                    line.Inlines.Add(new Run(textLine));
                }
                line.Inlines.Add(new LineBreak());
                output.Inlines.Add(line);
            }
        }

        Process _cmd;
    }
}
1 голос
/ 06 мая 2010

Да - создайте процесс, используя Process.Start(ProcessStartInfo), установив RedirectStandardOutput (и потенциально RedirectStandardError) в значение true и UseShellExecute в false на ProcessStartInfo, описывающем процесс, который вы хотите запустить.

Затем вы можете либо читать напрямую из Process.StandardOutput и Process.StandardError (в отдельных потоках, чтобы ничто не блокировалось, если процесс заполнил свой выходной буфер), либо подписаться на Process.OutputDataReceived событие и вызов Process.BeginOutputReadLine (и эквивалент для стандартной ошибки). В MSDN есть образцы всего этого.

Обратите внимание, что в любом случае вы будете получать данные из потока, отличного от потока пользовательского интерфейса, поэтому вам нужно будет использовать Control.Invoke / Control.BeginInvoke, чтобы выполнить маршалинг обратно в поток пользовательского интерфейса до того, как добавление текста в TextBox.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...