Non è possibile inviare comandi a una shell in questo modo. La stringa in info.Arguments è gli argomenti forniti al programma sulla riga di comando. Se si desidera che la shell di cmd.exe esegua una serie di comandi e quindi si esce, sarà necessario fornire l'argomento/c. Se hai più comandi da eseguire, dovrai inserire i comandi in un file batch ed eseguirli o racchiuderli tra virgolette e separarli con & &, ad esempio info.Arguments = @"/c ""cd \ && dir""";
. L'altro problema con il non ritorno è che cmd.exe si apre in modalità interattiva per impostazione predefinita quando viene eseguito senza argomenti, o appropriati. L'opzione/c indica a cmd.exe di eseguire i comandi rilevanti e quindi di uscire.
Inoltre, interpreti come python e perl a volte hanno comportamenti strani quando vengono lanciati direttamente da ProcessStartInfo. Se info.Arguments = @"""MyPerlProgram.pl""";
con perl.exe non funziona, potrebbe essere necessario avviarli all'interno di cmd.exe per ottenere un comportamento normale, ad es. info.Arguments = @"/c ""perl.exe ""MyPerlProgram.pl""""";
.
Vedere Cmd e ProcessStartInfo.Arguments Property.
Per rispondere al problema Modifica 3, probabilmente non si aggancia correttamente alle uscite. Invece di provare ad agganciare il BaseStream di StreamReader, collegare l'evento OutputDataReceived con this.shellProcess.OutputDataReceived += ProcessOutputHandler;
prima di chiamare Start dove ProcessOutputHandler ha una firma come public static void ProcessOutputHandler(object sendingProcess, DataReceivedEventArgs outLine)
. Subito dopo aver chiamato Start, chiama this.shellProcess.BeginOutputReadLine();
. Il processo è simile anche all'uscita errore. Vedere Process.BeginOutputReadLine Method e Process.BeginErrorReadLine Method per ulteriori dettagli.
Se hai ancora un problema, cosa ottieni se ti limiti a provare process.StartInfo.Arguments = @"/c ""python.exe -c ""import sys; print 'Test.';""""";
?
Inoltre, il codice qui sotto dimostra la maggior parte dei concetti necessari per la comunicazione shell:
public static void Main()
{
using (Process process = new Process())
{
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.WorkingDirectory = @"C:\";
process.StartInfo.FileName = Path.Combine(Environment.SystemDirectory, "cmd.exe");
// Redirects the standard input so that commands can be sent to the shell.
process.StartInfo.RedirectStandardInput = true;
// Runs the specified command and exits the shell immediately.
//process.StartInfo.Arguments = @"/c ""dir""";
process.OutputDataReceived += ProcessOutputDataHandler;
process.ErrorDataReceived += ProcessErrorDataHandler;
process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
// Send a directory command and an exit command to the shell
process.StandardInput.WriteLine("dir");
process.StandardInput.WriteLine("exit");
process.WaitForExit();
}
}
public static void ProcessOutputDataHandler(object sendingProcess, DataReceivedEventArgs outLine)
{
Console.WriteLine(outLine.Data);
}
public static void ProcessErrorDataHandler(object sendingProcess, DataReceivedEventArgs outLine)
{
Console.WriteLine(outLine.Data);
}
Si può avere problemi di threading che causano i vostri problemi. Ho fatto qualche ulteriore lavoro con questa ed è stato in grado di ottenere una casella di testo in un modulo per aggiornare con il seguente codice:
using System;
using System.Diagnostics;
using System.IO;
using System.Timers;
namespace DummyFormsApplication
{
class ProcessLauncher : IDisposable
{
private Form1 form;
private Process process;
private bool running;
public bool InteractiveMode
{
get;
private set;
}
public ProcessLauncher(Form1 form)
{
this.form = form;
process = new Process();
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.WorkingDirectory = @"C:\";
process.StartInfo.FileName = Path.Combine(Environment.SystemDirectory, "cmd.exe");
// Redirects the standard input so that commands can be sent to the shell.
process.StartInfo.RedirectStandardInput = true;
process.OutputDataReceived +=new DataReceivedEventHandler(process_OutputDataReceived);
process.ErrorDataReceived += new DataReceivedEventHandler(process_ErrorDataReceived);
process.Exited += new EventHandler(process_Exited);
}
public void Start()
{
if (running == false)
{
running = true;
InteractiveMode = true;
// Runs the specified command and exits the shell immediately upon completion.
process.StartInfo.Arguments = @"/c ""C:\python27\python.exe -i""";
process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
}
}
public void Start(string scriptFileName)
{
if (running == false)
{
running = true;
InteractiveMode = false;
// Runs the specified command and exits the shell immediately upon completion.
process.StartInfo.Arguments = string.Format(@"/c ""C:\python27\python.exe ""{0}""""", scriptFileName);
}
}
public void Abort()
{
process.Kill();
}
public void SendInput(string input)
{
process.StandardInput.Write(input);
process.StandardInput.Flush();
}
private void process_OutputDataReceived(object sendingProcess, DataReceivedEventArgs outLine)
{
if (outLine.Data != null)
{
form.Invoke(form.appendConsoleTextDelegate, new object[] { outLine.Data });
}
}
private void process_ErrorDataReceived(object sendingProcess, DataReceivedEventArgs outLine)
{
if (outLine.Data != null)
{
form.Invoke(form.appendConsoleTextDelegate, new object[] { outLine.Data });
}
}
private void process_Exited(object sender, EventArgs e)
{
running = false;
}
public void Dispose()
{
if (process != null)
{
process.Dispose();
}
}
}
}
ho creato un modulo e aggiunto una casella di testo e il seguente codice nella forma:
public delegate void AppendConsoleText(string text);
public AppendConsoleText appendConsoleTextDelegate;
private void Form1_Load(object sender, EventArgs e)
{
appendConsoleTextDelegate = new AppendConsoleText(textBox1_AppendConsoleText);
using (ProcessLauncher launcher = new ProcessLauncher(this))
{
launcher.Start();
launcher.SendInput("import sys;\n");
launcher.SendInput("print \"Test.\";\n");
launcher.SendInput("exit()\n");
}
}
private void textBox1_AppendConsoleText(string text)
{
textBox1.AppendText(string.Format("{0}\r\n", text));
}
Una cosa da notare è che se l'evento Form1_Load non viene completato, Invoke si bloccherà fino a quando non lo farà. Se in un evento è presente codice con esecuzione prolungata, è necessario richiamare in modo asincrono utilizzando BeginInvoke o chiamare periodicamente DoEvents nel codice di vecchia esecuzione.
EDIT
Per il tuo commento, ho modificato il codice per lavorare con mezzi interattivi. C'è, tuttavia, un problema. Il prompt python (>>>
) viene fornito sull'output StandardError e non fa eco a StandardInput. Inoltre non termina la linea. Ciò rende difficile il rilevamento di un prompt e causa la fuoriuscita dell'ordine dei caratteri di prompt a causa del fatto che process_ErrorDataReceived non viene attivato fino a quando il processo non termina o viene visualizzata una fine riga.
Ciao Jamie, può fornire un esempio o un collegamento che potrebbe aiutare, per favore? – Gagan
Risposta aggiornata con un esempio di informazioni.Argomandi per cmd.exe e aggiunta spiegazione del motivo per cui il processo non termina mai da solo. – JamieSee
Risposta aggiornata con soluzione per Modifica 3. – JamieSee