Код: Выделить всё
public static class Exec
{
public delegate void OutputHandler(String line);
//
/// Run a command in a subprocess
///
///
Directory from which to execute the command
/// Command to execute
/// Arguments for command
/// Command output handler (null if none)
/// True if no windows is to be shown
/// Exit code from executed command
public static int Run(String path, String cmd, String args,
OutputHandler hndlr = null, Boolean noshow = true)
{
// Assume an error
int ret = 1;
// Create a process
using (var p = new Process())
{
// Run command using CMD.EXE
// (this way we can pipe STDERR to STDOUT so they can get handled together)
p.StartInfo.FileName = "cmd.exe";
// Set working directory (if supplied)
if (!String.IsNullOrWhiteSpace(path)) p.StartInfo.WorkingDirectory = path;
// Indicate command and arguments
p.StartInfo.Arguments = "/c \"" + cmd + " " + args + "\" 2>&1";
// Handle noshow argument
p.StartInfo.CreateNoWindow = noshow;
p.StartInfo.UseShellExecute = false;
// See if handler provided
if (hndlr != null)
{
// Redirect STDOUT and STDERR
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.RedirectStandardError = true;
// Use custom event handler to capture output
using (var outputWaitHandle = new AutoResetEvent(false))
{
p.OutputDataReceived += (sender, e) =>
{
// See if there is any data
if (e.Data == null)
{
// Signal output processing complete
outputWaitHandle.Set();
}
else
{
// Pass string to string handler
hndlr(e.Data);
}
};
// Start process
p.Start();
// Begin async read
p.BeginOutputReadLine();
// Wait for process to terminate
p.WaitForExit();
// Wait on output processing complete signal
outputWaitHandle.WaitOne();
}
}
else
{
// Start process
p.Start();
// Wait for process to terminate
p.WaitForExit();
}
// Get exit code
ret = p.ExitCode;
}
// Return result
return ret;
}
//
/// Run a command in a subprocess and return output in a variable
///
/// Directory from which to execute the command
/// Command to execute
/// Arguments for command
/// Variable to contain the output
/// Exit code from executed command
public static GetOutputReturn GetOutput(String path, String cmd, String args)
{
GetOutputReturn ret = new GetOutputReturn();
ret.ReturnCode = Run(path, cmd, args, (line) =>
{
ret.Output.AppendLine(line);
});
return ret;
}
}
public class GetOutputReturn
{
public StringBuilder Output = new StringBuilder();
public int ReturnCode = 1;
}
Код: Выделить всё
static void Main(string[] args)
{
int ret;
Console.WriteLine("Executing dir with no capture and no window");
ret = Exec.Run(@"C:\", "dir", "");
Console.WriteLine("Execute returned " + ret);
Console.WriteLine("Press enter to continue ...");
Console.ReadLine();
Console.WriteLine("Executing dir with no capture and window");
ret = Exec.Run(@"C:\", "dir", "", null, false);
Console.WriteLine("Execute returned " + ret);
Console.WriteLine("Press enter to continue ...");
Console.ReadLine();
Console.WriteLine("Executing dir with capture and no window");
var results = Exec.GetOutput(@"C:\", "dir", "");
Console.WriteLine(results.Output.ToString());
Console.WriteLine("Execute returned " + results.ReturnCode);
Console.ReadLine();
Console.WriteLine("Executing dir with real-time capture and no window");
ret = Exec.Run(@"C:\", "dir", "", ShowString);
Console.WriteLine("Execute returned " + ret);
}
public delegate void StringData(String str);
static void ShowString(String str)
{
Console.WriteLine(str);
}
public delegate void StringData(String str);
static void ShowString(String str)
{
Console.WriteLine(str);
}
Второй запуск не собирает никаких выходных данных, но показывает окно.
В результате выходные данные появляются в окне консоли в режиме реального времени.
Третий запуск использует GetOutput для сбора выходных данных.
В результате этого выходные данные не появляются до завершения выполнения.
Последний запуск использует обработчик для получения и отображения выходных данных в режиме реального времени.
Внешне это похоже на второй запуск, но он сильно отличается.
Для каждой полученной строки вывода вызывается ShowString.
Show string просто отображает строку.
Однако он может делать с данными все, что ему нужно.
Я пытаюсь адаптировать последний запуск так, чтобы можно было обновлять текстовое поле с выводом команды в режиме реального времени. Проблема, с которой я столкнулся, заключается в том, как получить это в правильном контексте (из-за отсутствия лучшего термина). Поскольку OutputHandler вызывается асинхронно, для синхронизации с потоком пользовательского интерфейса он должен использовать механизм InvokeRequired/BeginInvoke/EndInvoke. У меня возникла небольшая проблема с тем, как это сделать с параметрами. В моем коде textBox может быть одним из нескольких в элементе управления вкладками, поскольку может иметь место несколько фоновых «Выполнить».
Пока у меня есть это:
Код: Выделить всё
private void btnExecute_Click(object sender, EventArgs e)
{
// Get currently selected tab page
var page = tcExecControl.SelectedTab;
// Get text box (always 3rd control on the page)
var txt = (TextBox)page.Controls[2];
// Create string handler
var prc = new Exec.OutputHandler((String line) =>
{
if (txt.InvokeRequired)
txt.Invoke(new MethodInvoker(() =>
{ txt.Text += line; }));
else txt.Text += line;
});
// Command and arguments are always 1st and 2nd controls on the page
var result = Exec.Run(@"C:\", page.Controls[0].Text, page.Controls[1], prc);
}
На самом деле программа в основном зависает в обработчике.
Если я изменю код на использование GetOutput, а затем запишу полученный вывод в текстовое поле, все будет работать. Итак, я знаю, что у меня настроена команда правильно. Используя отладчик, я могу установить точку останова на "if (
Код: Выделить всё
txt.InvokeRequiredКод: Выделить всё
txt.Text += line;Может ли кто-нибудь мне помочь? Я уверен, что что-то упускаю.
Подробнее здесь: https://stackoverflow.com/questions/516 ... -real-time
Мобильная версия