2012-08-01 11 views
6

私の実装の1つとして、コマンド/結果をcmdウィンドウとの間で送受信するツールに取り組んでいます。すべてうまくいきますが、以下のユースケースでは何もしません。アプリケーションが(結果を表示する代わりに)何かを待っているかのようです。C#のコマンドプロンプトへのコマンドの送信

私のツールから私はpythonフォルダに移動します。 pythonフォルダからpython.exeを起動しようとしていますが、この時点ではエディタは何もしません。単に待っているだけです。

私はここでもビデオをリンクしています。皆さんが私が何を言おうとしているのかを理解することは、より簡単になります。

View the Video here (on youtube)

私はまた私が現在持っているコードを添付しています。

  ProcessStartInfo info = new ProcessStartInfo("cmd.exe"); 

      string argument = null; 
      if (!string.IsNullOrEmpty(startingDirectory) && System.IO.Directory.Exists(startingDirectory)) 
      { 
       argument += @"cd\"; 
      } 
      else 
      { 
       argument += "\""; 
      } 
      info.Arguments = argument; 
      info.CreateNoWindow = true; 
      info.RedirectStandardError = true; 
      info.RedirectStandardInput = true; 
      info.RedirectStandardOutput = true; 
      info.UseShellExecute = false; 
      this.shellProcess = System.Diagnostics.Process.Start(info); 
      this.shellProcess.EnableRaisingEvents = true; 
      //this.InputStream.AutoFlush = true; 
      this.shellProcess.Exited += new EventHandler(ProcessExited); 
      this.ErrorBeginRead(); 
      this.OutputBeginRead(); 

private void OutputBeginRead() 
    { 
     this.shellProcess.StandardOutput.BaseStream.BeginRead(outputBuffer, 0, outputBuffer.Length, new AsyncCallback(this.OnOutputInput), this.shellProcess); 
    } 

     private void ErrorBeginRead() 
    { 
     this.shellProcess.StandardError.BaseStream.BeginRead(errorBuffer, 0, errorBuffer.Length, new AsyncCallback(this.OnErrorInput), this.shellProcess); 
    } 

ありがとうございます!

編集: Pythonを起動するのは単なる例です。他の通常のcmd行コマンドにも同じ方法を使用する必要があります。意図した機能を達成するために、自分が持っているコードや何をしなければいけないのかを誰かが指摘できるなら、いいでしょう。

EDIT 2:通常のcmdコマンドは完全に機能しています。 python、perlのようなコマンドラインツールは動作しません。

編集3:私はJamieの提案に従って少し前進しました。 uiはもはや「ぶら下がり」していません。しかし、Pythonインタプリタにアクセスすると、インタプリタの出力は私のツールでは見えません。なぜそれが起こっているかもしれないのか?

答えて

15

このようにシェルにコマンドを送信することはできません。 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がプロセスが終了するか、行末が表示されるまでプロンプト文字が出力されなくなります。

+0

こんにちはジェイミー、助けてくれる例やリンクを教えてください。 – Gagan

+0

cmd.exe用のinfo.Argumentsの例を挙げて説明し、プロセスがそれ自身で終了しない理由についての説明を追加しました。 – JamieSee

+0

編集3の解答を更新しました。 – JamieSee

2

質問には、アプリケーションが掛かっているものを正確に把握するのに十分なコードがありません。あなたのコードには奇妙に見えるものがいくつかあります。たとえば、Processクラスに組み込まれているものを使用する代わりに、独自のエラーを出して出力ループを出力するのはなぜですか?このように:

var shellProcess = System.Diagnostics.Process.Start(info); 
shellProcess.EnableRaisingEvents = true; 
shellProcess.Exited += ProcessExited; 

shellProcess.OutputDataReceived += ShellProcess_OutputDataReceived; 
shellProcess.ErrorDataReceived += ShellProcess_ErrorDataReceived; 
shellProcess.BeginOutputReadLine(); 
shellProcess.BeginErrorReadLine(); 

void ShellProcess_ErrorDataReceived(object sender, DataReceivedEventArgs e) 
{ 
    // Do Something 
} 

void ShellProcess_OutputDataReceived(object sender, DataReceivedEventArgs e) 
{ 
    // Do Something 
} 

あなたのエラー出力非同期イベントが発射されていないので、それはshellProcessと寿命の問題があるかもしれないと信じて私をリード。より多くのコードを投稿すれば、より良い指針を与えることができます。

1

は、私はすべてのあなたのコードを見ることはできませんが、簡単使用スチームオブジェクトは、書き込み/あなたによって作成されたCMDウィンドウにコマンドを送信することができます。例えば:例えば上記の例では

StreamWriter inputStream = shellProcess.StandardInput; 
//send command to cmd prompt and wait for command to execute with thread sleep 
inputStream.WriteLine("echo "CMD just received input"); 
inputStream.Flush(); 

、コマンドプロンプトは、それが窓に入力されただけのようechoコマンドを受信します。出力を表示するには、StreamReaderオブジェクトを作成し、それをプロセスのStandardOutputに割り当てる必要があります。

+0

余分な手荷物はありませんか? – Gagan

関連する問題