Действительно ли возможно запустить какую-либо основанную на командной строке программу или пакетный файл и capturer (перенаправление) помещенный в текстовое поле LIVE
CL занимает время, и он производит текст!
что-то как tracert.exe (это занимает время и производит хорошую сумму текста).
на самом деле я буду работать с tracert.exe, и мне нравится получать живой вывод и показывать его в текстовом поле, в то время как это работает
Править: Моя проблема состоит в том, чтобы иметь его ЖИВОЙ, я имею в виду любую новую строку или обугливаюсь, консольный продукт будет отправлен/вытянут в текстовое поле, Только когда программа сделана!
Просто я хочу создать, точно похож на этот 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();
}
Править
с Вашей справкой (большое спасибо парни) и эта ссылка: 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);
}
}
}
}
Когда вы создаете экземпляр 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;
}
}
Да - создайте процесс, используя Process.Start (ProcessStartInfo)
, установив для RedirectStandardOutput
(и, возможно, RedirectStandardError
) значение true и UseShellExecute
] на false в ProcessStartInfo
, описывающей процесс, который вы хотите запустить.
Затем вы можете либо читать напрямую из Process.StandardOutput
и Process.StandardError
(в отдельных потоках, чтобы ничего не блокировалось, если процесс заполняет свой выходной буфер), либо подписаться на Событие Process.OutputDataReceived
и вызов Process.BeginOutputReadLine
(и эквивалент для стандартной ошибки). В MSDN есть образцы всего этого.
Обратите внимание, что в любом случае вы будете получать данные в потоке, отличном от потока пользовательского интерфейса, поэтому вы захотите использовать Control.Invoke
/ Control.BeginInvoke
для маршалинга обратно в поток пользовательского интерфейса перед
добавлением текста в TextBox.