Запустить процесс в текущей консоли

Я пишу базовую оболочку для Windows, и мне было интересно, есть ли способ запустить подпроцесс (Process process), чтобы он использовал текущее окно консоли. Под этим я подразумеваю, что я не хочу перенаправлять ввод/вывод; Я хочу, чтобы процесс принимал ввод с текущей консоли и печатал вывод непосредственно в том же окне консоли.

Причина в том, что я хочу разрешить этому подпроцессу устанавливать цвета консоли для вывода, чего не может произойти, если я перенаправляю стандартный вывод процесса. Кроме того, я в настоящее время использую код

while (!process.HasExited)
    process.StandardInput.WriteLine(Console.ReadLine());

для перенаправления стандартного ввода в процесс. Однако, если процесс выходит сразу после ввода (например, я набираю "exit" + ENTER, и процесс завершается), этот цикл будет запускаться еще раз, поэтому консоль ожидает ввода от пользователя, который никогда не будет использоваться процессом (он должен выйти).

Итак, длинный короткий вопрос, , как я могу запустить процесс в текущей консоли, чтобы он мог устанавливать цвета консоли и напрямую принимать входные данные с консоли?

Изменить: Ниже приведены методы, относящиеся к этому вопросу из моего кода:

static int runExe(string exePath, params string[] args)
{
    ProcessStartInfo startInfo = new ProcessStartInfo(exePath, args)
    {
        ErrorDialog = false,
        UseShellExecute = false,
        CreateNoWindow = true,
        RedirectStandardInput = true,
        RedirectStandardOutput = true,
        RedirectStandardError = true,
        RedirectStandardInput = true
    };
    Process process = new Process() { StartInfo = startInfo };
    process.Start();
    ReadThreadState stdout = readThread(process.StandardOutput, false);
    ReadThreadState stderr = readThread(process.StandardError, true);
    while (!process.HasExited)
        process.StandardInput.WriteLine(Console.ReadLine());
    stdout.stop = stderr.stop = true;
    return process.ExitCode;
}
class ReadThreadState
{
    public bool stop;
}
private static ReadThreadState readThread(StreamReader reader, bool isError)
{
    ReadThreadState state = new ReadThreadState();
    new Thread(() =>
    {
        while (!state.stop)
        {
            int current;
            while ((current = reader.Read()) >= 0)
                if (isError)
                    writeError(((char)current).ToString(), ConsoleColor.Red);
                else
                    Console.Write((char)current);
        }
    }).Start();
    return state;
}

Ответы

Ответ 1

Вам нужно создать ProcessStartInfo и установить UseShellExecute в false:

var info = new ProcessStartInfo("program.exe", "arguments");
info.UseShellExecute = false;
var proc = Process.Start(info);
proc.WaitForExit();

Это запустит вашу программу в той же консоли.

Рабочая программа, использующая описанную выше технику:

private static void Main(string[] args)
{
    Console.WriteLine("Starting program");
    var saveColor = Console.BackgroundColor;
    Console.BackgroundColor = ConsoleColor.Blue;
    var info = new ProcessStartInfo("cmd", "/c time");
    info.UseShellExecute = false;
    var proc = Process.Start(info);
    proc.WaitForExit();

    Console.BackgroundColor = saveColor;
    Console.WriteLine("Program exited");
    Console.ReadLine();
}

Когда вы запускаете программу, она запускает новую копию cmd.exe и запускает команду time, которая запрашивает ввод. Я просто использовал cmd.exe в качестве примера здесь, чтобы проиллюстрировать. Любая программа, которая читает со стандартного ввода, будет работать. Также обратите внимание, что цвета консоли работают правильно.

Ответ 2

Ответ Джима Мишеля работает как шарм. Я перемещаю обработку пакетных файлов на С#, и это отлично работает. Вы можете найти этот небольшой метод полезности. Просто берет командную строку и запускает ее так же, как CALL в пакетном файле. Просто введите его в класс утилиты:

public static void RunCmd(string command) {
    Process.Start(new ProcessStartInfo("cmd.exe", "/c " + command) {
        UseShellExecute = false
    }).WaitForExit();            
}