このようにシェルにコマンドを送信することはできません。 info.Argumentsの文字列は、コマンドラインでプログラムに渡される引数です。 cmd.exeシェルで一連のコマンドを実行して終了するには、/ c引数を指定する必要があります。複数のコマンドを実行する場合は、コマンドをバッチファイルに入れて実行するか、引用符で囲んで& &というように区切らなければなりません。すなわち、info.Arguments = @"/c ""cd \ && dir""";
です。戻ってこないというあなたの他の問題は、cmd.exeが何も適切な引数なしで実行されると、デフォルトで対話モードで開きます。/cオプションは、関連するコマンドを実行して終了するようにcmd.exeに指示します。
さらに、pythonやperlのようなインタプリタは、ProcessStartInfoから直接起動すると奇妙な動作をすることがあります。 perl.exeでinfo.Arguments = @"""MyPerlProgram.pl""";
が動作しない場合は、cmd.exe内で起動して正常な動作を得る必要があります。つまり、info.Arguments = @"/c ""perl.exe ""MyPerlProgram.pl""""";
です。
CmdおよびProcessStartInfo.Arguments Propertyを参照してください。
編集3の問題には、正しく出力にフックされていない可能性があります。 StreamReaderのBaseStreamをフックするのではなく、Startを呼び出す前にOutputDataReceivedイベントをthis.shellProcess.OutputDataReceived += ProcessOutputHandler;
にフックします。ここでProcessOutputHandlerにはpublic static void ProcessOutputHandler(object sendingProcess, DataReceivedEventArgs outLine)
のようなシグネチャがあります。 Startを呼び出した直後にthis.shellProcess.BeginOutputReadLine();
と呼んでください。このプロセスは、エラー出力でも同様です。詳細については、Process.BeginOutputReadLine MethodおよびProcess.BeginErrorReadLine Methodを参照してください。
問題が解決しない場合は、process.StartInfo.Arguments = @"/c ""python.exe -c ""import sys; print 'Test.';""""";
を試してみるとどうなりますか?
また、以下のコードは、シェルの通信に必要な概念のほとんどを示しています
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);
}
あなたはあなたの問題を引き起こしてスレッドの問題を有することができます。私はこれをさらにいくつかの仕事をして、次のコードを更新するために、フォーム上のテキストボックスを取得することができたました:
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();
}
}
}
}
私は、フォームを作成し、フォームにテキストボックスと次のコードを追加しました:
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));
}
Form1_Loadイベントが完了しないと、Invokeは終了するまでハングします。あるイベントに長期実行コードがある場合は、BeginInvokeを使用して非同期に呼び出すか、長時間実行しているコードで定期的にDoEventsを呼び出す必要があります。あなたのコメントパー
EDIT
、私は対話の提出で動作するようにコードを修正しました。しかし、問題があります。 Pythonプロンプト(>>>
)はStandardError出力に提供され、StandardInputをエコーしません。また、行を終了しません。これによりプロンプトが検出されにくくなり、process_ErrorDataReceivedがプロセスが終了するか、行末が表示されるまでプロンプト文字が出力されなくなります。
こんにちはジェイミー、助けてくれる例やリンクを教えてください。 – Gagan
cmd.exe用のinfo.Argumentsの例を挙げて説明し、プロセスがそれ自身で終了しない理由についての説明を追加しました。 – JamieSee
編集3の解答を更新しました。 – JamieSee