Интерактивная консоль ввода-вывода Оболочка / Перехватчик в C # - В чем проблема? - PullRequest
3 голосов
/ 24 мая 2010

В течение выходных я пытался собрать интерактивный консольный перехватчик / упаковщик в C #, повторно смешав несколько примеров кода, которые я нашел на SO и других сайтах.

С тем, что у меня есть сейчас, я не могу надежно читать с консоли. Есть быстрые указатели?

public class ConsoleInterceptor
{
    Process _interProc;

    public event Action<string> OutputReceivedEvent;

    public ConsoleInterceptor()
    {
        _interProc = new Process();
        _interProc.StartInfo = new ProcessStartInfo("cmd");
        InitializeInterpreter();
    }

    public ConsoleInterceptor(string command)
    {
        _interProc = new Process();
        _interProc.StartInfo = new ProcessStartInfo(command);
        InitializeInterpreter();
    }

    public Process InterProc
    {
        get
        {
            return _interProc;
        }
    }

    private void InitializeInterpreter()
    {
        InterProc.StartInfo.RedirectStandardInput = true;
        InterProc.StartInfo.RedirectStandardOutput = true;
        InterProc.StartInfo.RedirectStandardError = true;
        InterProc.StartInfo.CreateNoWindow = true;
        InterProc.StartInfo.UseShellExecute = false;
        InterProc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
        bool started = InterProc.Start();

        Redirect(InterProc.StandardOutput);
        Redirect(InterProc.StandardError);

    }

    private void Redirect(StreamReader input)
    {
        new Thread((a) =>
        {
            var buffer = new char[1];
            while (true)
            {
                if (input.Read(buffer, 0, 1) > 0)
                    OutputReceived(new string(buffer));
            };
        }).Start();
    }

    private void OutputReceived(string text)
    {
        if (OutputReceivedEvent != null)
            OutputReceivedEvent(text);
    }


    public void Input(string input)
    {
        InterProc.StandardInput.WriteLine(input);
        InterProc.StandardInput.Flush();
    }
}

Чего я пытаюсь достичь? Вот минимальный вариант использования. Предположим, у меня есть два текстовых поля.

//Create my interceptor
 ConsoleInterceptor interc = new ConsoleInterceptor("cmd");
//Show the output in a textbox
     interc.OutputReceivedEvent += (data) =>
                {
                    this.Invoke(new Action<string>((s)=> this.textBoxOut.Text += s) ,data);
                };



 //Capture user input and pass that to the above interceptor
  private void textInput_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
            {
                interc.Input(textInput.Text);
            }
        }

Ответы [ 2 ]

1 голос
/ 24 мая 2010

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

В ссылке приведен полный пример, который, надеюсь, поможет.

0 голосов
/ 24 мая 2010

Для полной совместимости с любым консольным процессом вам необходимо три отдельных потока: одна запись в stdin, одна запись из stdout и одна запись из stderr. Это в дополнение к вашей основной теме. В вашем примере кода есть только один из трех необходимых потоков (стандартный вывод).

...