Я пытаюсь написать оболочку для интерактивного консольного приложения. Для этого я использую 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
) использует несколько потоков ...
Но как это решить?