Перенаправление стандартных потоков ввода / вывода / ошибок с помощью класса процессов .NET - PullRequest
6 голосов
/ 16 августа 2011

Я пытаюсь написать оболочку для интерактивного консольного приложения. Для этого я использую C # и класс Process. Я пытаюсь перенаправить stdin / out / err, но это не работает.

Пример кода:

ProcessStartInfo startInfo = new ProcessStartInfo("admin.exe");
startInfo.RedirectStandardOutput = true;
startInfo.RedirectStandardError = true;
startInfo.RedirectStandardInput = true;
startInfo.UseShellExecute = false;

Process process = Process.Start(startInfo);
process.BeginOutputReadLine();
process.BeginErrorReadLine();
process.OutputDataReceived += (s, e) => Console.WriteLine(e.Data);
process.ErrorDataReceived += (s, e) => Console.WriteLine(e.Data);

while (true)
{
    process.StandardInput.Write("uptime" + Environment.NewLine);
    process.StandardInput.Flush();
    Thread.Sleep(1000);
}
Console.ReadKey();

Ничего не происходит. Но если я начну admin.exe и напишу uptime, вывод будет напечатан.

Все решения в Интернете используют ReadToEnd, но я не могу использовать это, потому что у меня есть динамическое общение, по которому я должен прочитать stdout / err и написать stdin.

У кого-нибудь есть идеи?

Обновление

Я играл с опубликованным почтовым индексом в связанной ветке. А потом я попытался создать небольшой код для проверки концепции:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.IO;
using System.Threading; 

namespace ConsoleApplication3
{
    class Program
    {
        private static void Read(StreamReader reader)
        {
            new Thread(() =>
                {
                    while (true)
                    {
                        int current;
                        while ((current = reader.Read()) >= 0)
                            Console.Write((char)current);
                    }
                }).Start();
        }

        static void Main(string[] args)
        {
            ProcessStartInfo startInfo = new ProcessStartInfo(@"cmd.exe");
            startInfo.CreateNoWindow = true;
            startInfo.ErrorDialog = false;
            startInfo.RedirectStandardError = true;
            startInfo.RedirectStandardInput = true;
            startInfo.RedirectStandardOutput = true;
            startInfo.UseShellExecute = false;
            startInfo.CreateNoWindow = true;
            Process process = new Process();
            process.StartInfo = startInfo;
            process.Start();
            Read(process.StandardOutput);
            Read(process.StandardError);
            while (true)
                process.StandardInput.WriteLine(Console.ReadLine());
        }
    }
}

Отлично работает: -)

Но с admin.exe это не работает? admin.exe не использует хитрый метод ввода и не требует ввода пароля.

Я знаю, что admin.exe написано на c и скомпилировано с помощью mingw на linux. Итак, я создал небольшой фиктивный инструмент:

#include <stdio.h>

int main() {
        int readed;
        while ((readed = fgetc(stdin)) >= 0)
                fputc((char)readed, stdout);
}

Этот инструмент отображает только введенный текст / строку. Я скомпилировал его с i586-mingw32msvc-gcc и скопировал на мой компьютер с Windows. Там я использовал программу в верхней части этого поста для связи с dummy.exe. Не работает Эхо не отображается. Но почему?

Я скомпилировал фиктивный код также с помощью компилятора Microsoft C ++, тот же эффект.

Update2

(кстати: спасибо Тиму Посту)

Я пытаюсь и пытаюсь. Я попытался создать c-Tool, который делает то же самое, что и мой инструмент c #. Я использовал _popen, но эффект был в том, что вывод был показан в конце процесса. Хм, не хорошо.

Я нашел эту альтернативную командную оболочку для Windows:

https://stackoverflow.com/questions/440269/whats-a-good-alternative-windows-console

http://sourceforge.net/projects/console/

Кажется, работает. Он получает stdout / err в реальном времени, может перенаправить стандартный ввод и admin.exe работает. И это с открытым исходным кодом. Может быть, я найду решение внутри C ++ - кода.

Я плохо разбираюсь в C ++, так что это сложно, но я попробую. Может быть, мне нужно написать «прозрачную» оболочку для перенаправления в C / C ++ и использовать ее в C #.

Если у кого-то есть идея, скажите, пожалуйста, потому что другой путь может быть очень сложным (для меня ^^): -)

Спасибо.

С наилучшими пожеланиями

Обновление 3

Хм, я думаю, это происходит потому, что дочерний процесс (admin.exe) использует несколько потоков ... Но как это решить?

1 Ответ

1 голос
/ 16 августа 2011

Проблема может быть из-за того, что вы используете Readline, когда данные выводятся из приложения admin.exe последовательно, а не в новых строках .., попробуйте вместо этого использовать Read,и построить из него желаемую строку ..

Также вам не нужно использовать Environment.NewLine для записи строки, за которой следует новая строка, вместо этого используйте WriteLine, поэтому:

process.StandardInput.WriteLine("uptime");
...