С# Shell - перенаправление ввода-вывода

Я пишу замену оболочки Windows на С#, и функция, которую я в настоящее время реализую, имеет все IO внутри одного окна оболочки, то есть не открывает cmd.exe в другом окне.

Сейчас у меня есть частичное решение для вывода. Это мой код (где p - текущий процесс):

while ( !p.HasExited ) {
    /* ... - irrelevant */
    if ( redirect ) {
        try {
            p.BeginOutputReadLine();
        } catch { }
    }
}

Процесс настраивается со всеми правильными свойствами, такими как UseShellExecute= False, RedirectStandard{Input, Output, Error}= True, и обработчики событий настроены правильно, но они несовместимы.

Я попытался вынуть try/catch (который, как я знаю, очень плохая практика), и используя занятый bool, который установлен на false при запуске обработчика, но по какой-то причине я все еще получаю InvalidOperationException на p.BeginOutputReadLine() - заявив, что уже выполняется асинхронная работа.

Любая помощь будет оценена, даже если для этого требуется совершенно другое решение выше, а не просто ее исправление.

Спасибо.

EDIT. Вот код, который запускает процесс:

if (redirect)
{
    p.StartInfo.RedirectStandardOutput = true;
    p.StartInfo.RedirectStandardError = true;
    p.StartInfo.RedirectStandardInput = true;
    p.StartInfo.UseShellExecute = false;
    p.OutputDataReceived += new DataReceivedEventHandler(redirectHandler_StdOut);
    p.ErrorDataReceived += new DataReceivedEventHandler(redirectHandler_StdErr);
}
p.Start();

Кроме того, я понял, что не объясняю, что я имею в виду под непоследовательностью. Как говорится, картина стоит 2^3 слов:

screenshot

Ответ 1

Методы с префиксом Begin обычно выполняются асинхронно. Это то, что вы хотите? Поскольку кажется, что цикл работает так быстро, как он может, вызывая все больше и больше BeginOutputReadLine (потому что вызов немедленно возвращается, прежде чем он это сделает, и цикл подходит для другой итерации).

Вы можете вызвать ReadLine в потоке StandardOutput для синхронного решения. Или:

    while ( !p.HasExited ) {
        /* ... - irrelevant */
        if ( redirect && !busy ) {
            try {
                busy = true;
                p.BeginOutputReadLine();
            } catch { }
        }
    }
   ////In the method that gets called upon completion of BeginOutputReadLine
   busy = false;

Помните об этом (из MSDN):

Когда асинхронные операции чтения start, обработчик события называется каждый раз связанный процесс записывает текст в текст Поток StandardOutput.

Вы можете отменить асинхронное чтение по вызову CancelOutputRead. Операцию чтения можно отменить вызывающего или обработчика события. После отмены вы можете позвонить BeginOutputReadLine снова возобновит асинхронные операции чтения.

Это заставляет меня полагать, что вы должны только вызвать этот метод один раз, и он будет уведомлять вас через обратный вызов, когда строка будет записана.