В процессе WinForm, как определить, когда дочерний процесс командной строки требует ввода? - PullRequest
1 голос
/ 20 сентября 2011

В приложении WinForm, которое вызывает сторонний инструмент командной строки, может быть время, когда инструмент ожидает ввода данных пользователем, например, спрашивает, следует ли перезаписать файл:

printf("%s already exists, overwrite?: <Y>es, <N>o, <A>ll, <Q>uit?",FName);
for ( ; ; )
    switch ( toupper(getch()) ) {
        case 'A':
            YesToAll=true;
        case '\r': 
        case 'Y':
            remove(FName);
            return true;
        case 0x1B: 
        case 'Q':
            printf("quit\n"); exit(-1);
        case 'N':                       
            return false;
    }

Когдав таком случае я хочу отобразить сообщение от printf() и параметры в диалоговом окне и перенаправить нажатие кнопки в качестве входных данных для процесса.Вероятно, для отправки ввода используется System.Diagnostics.Process.StandardInput.Но не зная, когда именно инструмент будет ожидать ввода, я бы не знал, когда реагировать соответствующим образом в графическом интерфейсе.Когда процесс находится в этом цикле for, мой процесс WinForm просто остановится.

РЕДАКТИРОВАНИЕ : вот код, который разблокирует пользовательский интерфейс, запустив процесс в другом потоке, однако я все еще не смог прочитать вывод, если выбранный файл вызовет перезапись инструмента.опции.proc_OutputDataReceived ( EDIT2 : или readStdOut в случае proc.StandardOutput.BaseStream.BeginRead) никогда не будет вызываться, если инструмент не запрашивает ввод).

    private BackgroundWorker worker = new BackgroundWorker();

    private void fileChosenHandler(object sender, EventArgs e)
    {
        OpenFileDialog dialog = sender as OpenFileDialog;
        worker.DoWork += new DoWorkEventHandler(worker_DoWork);
        worker.RunWorkerAsync(dialog.FileName);
    }

    private void worker_DoWork(object sender, DoWorkEventArgs e)
    {
        string exePath = @"F:\test\test.exe";
        Process proc = new Process();
        proc.StartInfo.FileName = exePath; 
        proc.StartInfo.Arguments = "\"" + (string)e.Argument + "\""; 
        proc.StartInfo.UseShellExecute = false; 
        proc.StartInfo.CreateNoWindow = true;
        proc.StartInfo.RedirectStandardOutput = true;
        proc.OutputDataReceived += new DataReceivedEventHandler(proc_OutputDataReceived);

        proc.Start();

        // method 1: read lines
        //proc.BeginOutputReadLine();
        // method 2: read characters
        proc.StandardOutput.BaseStream.BeginRead(stdOutBuffer, 0, stdOutBuffer.Length, readStdOut, proc);

        proc.WaitForExit();

    }

    private void proc_OutputDataReceived(object sender, DataReceivedEventArgs e)
    {
        MessageBox.Show("Output: " + e.Data);
    }

    private byte[] stdOutBuffer = new byte[20]; 

    private void readStdOut(IAsyncResult result)
    {
        Process proc = result.AsyncState as Process;

        int bytesNumber = proc.StandardOutput.BaseStream.EndRead(result);
        if (bytesNumber != 0)
        {
            string text = System.Text.Encoding.ASCII.GetString(stdOutBuffer, 0, bytesNumber);
            MessageBox.Show("Output: " + text);
        }

        // set up the callback again
        proc.StandardOutput.BaseStream.BeginRead(stdOutBuffer, 0, stdOutBuffer.Length, readStdOut, proc);
    }

Любая идеякак это сделать?Спасибо!

1 Ответ

2 голосов
/ 20 сентября 2011

Чтение из System.Diagnostics.StandardOutput (если вы используете блокирующее чтение, вам придется делать это в отдельном потоке), пока не найдете соответствие для этой строки, затем отобразите свое окно сообщения и отправьте символ на StandardInput из процесс по выбору пользователя.

<ч />

Краткое описание того, что мы попробовали:

  • «обычное» асинхронное чтение с BeginOutputReadLine ->, безусловно, завершается ошибкой, поскольку сообщение из приложения не завершается с '\n';
  • асинхронное чтение в 1-байтовых блоках ->, похоже, происходит сбой, поскольку приложение не очищает буфер;
  • добавление fflush(stdout) к приложению C + предыдущий подход: успех! Очевидно, что программа не очищала буфер вывода до getch().

Интересно, что этого, вероятно, не произойдет в приложении C ++, использующем стандартные iostreams, поскольку cin привязан к cout, и до того, как произойдет любая операция ввода в cin, cout автоматически сбрасывается. Я подумал, что было бы разумно, чтобы что-то подобное произошло и для stdin / stdout, но я не могу найти ссылку на него в стандарте (также факт, что chat getch() нестандартен и отличается от других Функции ввода-вывода, будучи небуферизованными, могут быть связаны между собой).

Подробнее см. В комментариях. :)

...