2012-08-01 47 views
6

Uygulamalarımdan biri için cmd penceresinden/komutlarına/komutları/sonuçları alması/çağırması gereken bir araç üzerinde çalışıyorum. Her şey iyi çalışıyor, ancak aşağıdaki durumu kullan, hiçbir şey yapamaz. Uygulamam bir şey bekliyor (sonuç görüntüleniyor yerine) gibi görünüyor.C# cm komut istemine komutları gönderme # C#

Aracımdan python klasörüne gidiyorum. Python klasöründen python.exe'yi başlatmaya çalışıyorum ama bu noktada editörüm hiçbir şey yapmıyor. Sadece beklemeye devam ediyor.

İlginiz için, videoyu da buraya bağlıyorum. Söylemeye çalıştığım şeyi anlamanız sizin için daha kolay olurdu.

View the Video here (on youtube)

Ben de şu anda sahip kod ekleme.

  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); 
    } 

Teşekkür ederiz!

DÜZENLEME: Python başlatmak sadece bir örnektir. Aynı yöntemi diğer normal cmd satırı komutları için de kullanmam gerekiyor. İstenilen işlevselliği elde etmek için, sahip olduğum ya da yapmam gereken kodla yanlış yaptığım biri işaret ederse, bu hoş olurdu.

DÜZEN 2: Normal cmd komutları mükemmel çalışıyor. Python, perl gibi komut satırı araçları çalışmıyor.

Düzenleme 3: Bu yüzden Jamie'nin önerilerini izleyerek bir çiş ilerletmeyi başardım. UI artık "asılı" değil. ancak python yorumlayıcısına eriştiğimde, tercümanın çıktısı hala aracımda görünmüyor. Bunun neden olabileceği hakkında herhangi bir öneriniz var mı?

cevap

15

Bu yolla bir kabuklara komut gönderemezsiniz. Info.Arguments içindeki dize, komut satırındaki programa sağlanan argümanlardır. Cmd.exe kabuğunun bir komut dizisini yürütmesini ve ardından çıkmasını istiyorsanız,/c argümanını sağlamanız gerekir. Eğer gerçekleştirmek istediğiniz birden çok komutunuz varsa, ya komutları bir toplu iş dosyasına yerleştirmeli ve bunları yürütmeli ya da bunları tırnak içine almalı ve bunları & &, yani info.Arguments = @"/c ""cd \ && dir"""; ile ayırmalısınız. Asla geri dönmeyecek olan diğer sorununuz, cmd.exe'nin herhangi bir ya da uygun argüman olmadan çalıştırıldığında varsayılan olarak etkileşimli modda açılmasından kaynaklanır./C seçeneği cmd.exe'ye ilgili komutları yürütmesini ve sonra çıkmasını söyler. Ayrıca, Python ve perl gibi çevirmenlerin, bazen doğrudan ProcessStartInfo'dan başlatıldığında garip davranışları vardır. info.Arguments = @"""MyPerlProgram.pl"""; with perl.exe çalışmıyorsa, onları, örn. info.Arguments = @"/c ""perl.exe ""MyPerlProgram.pl"""""; yerine normal davranış göstermek için cmd.exe dosyasının içinde başlatmak gerekir.

Bkz. Cmd ve ProcessStartInfo.Arguments Property.

Sorununuzu yanıtlamak için, 3 numaralı sorunu bildirin, muhtemelen çıkışlara yanlış takılmamış olabilirsiniz. StreamReader'ın BaseStream'i kancalamaya çalışmak yerine, ProcessOutputHandler'ın public static void ProcessOutputHandler(object sendingProcess, DataReceivedEventArgs outLine) gibi bir imzası olduğu Start'ı çağırmadan önce OutputDataReceived olayını this.shellProcess.OutputDataReceived += ProcessOutputHandler; ile kancalayın. Başlat'ı aradıktan hemen sonra, this.shellProcess.BeginOutputReadLine();'u arayın. İşlem, hata çıkışında da benzerdir. Daha fazla ayrıntı için bkz. Process.BeginOutputReadLine Method ve Process.BeginErrorReadLine Method.

Eğer hala bir probleminiz varsa, process.StartInfo.Arguments = @"/c ""python.exe -c ""import sys; print 'Test.';""""";'u denerseniz, ne elde edersiniz?

Ayrıca, kod aşağıda kabuk iletişim için gerekli kavramların çoğu gösterir: Eğer sorunlara neden parçacığı sorunları olabilir

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); 
} 

. Bununla bazı başka çalışma yaptık ve aşağıdaki kodla güncellemek için bir form üzerinde bir metin kutusu elde edebilir ettik:

: Ben bir form oluşturulur ve bir metin kutusu ve form aşağıdaki kodu eklendi
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)); 
    } 

Unutulmaması gereken bir şey, eğer Form1_Load olayı tamamlanmazsa, Invoke bunu yapana kadar askıda kalacaktır. Bir etkinlikte uzun süredir devam eden bir kodunuz varsa, BeginInvoke kullanarak senkronize olmayan bir şekilde çağırmanız veya uzun süren kodunuzda periyodik olarak DoEvent'leri çağırmanız gerekir.

DÜZENLEME Yorumlarınız Başına

, ben interaktif gönderimleri ile çalışmak için kod modifiye ettik. Bununla birlikte, bir sorun var. Python istemi (>>>) StandardError çıktısında sağlanmıştır ve StandardInput'u yansıtmaz. Ayrıca hattı sonlandırmaz. Bu, işlemin sonlanmasının zorlaşmasını ve işlem bitene veya satır sonu görünene kadar process_ErrorDataReceived'e bağlı olarak komut istemcisinin bazı sipariş çıkışlarının çıkmasına neden olur.

+0

Merhaba Jamie, Lütfen yardımcı olabilecek bir örnek veya bağlantı sunabilir misiniz, lütfen? – Gagan

+0

Bir örnek info.Arguments cmd.exe için cevabın üstesinden gelinmiş ve sürecin neden kendi başına bitmediğine dair açıklama ekledi. – JamieSee

+0

Güncelleme 3 ile ilgili çözümle ilgili yanıt güncellendi. – JamieSee

2

Uygulamanızın tam olarak nelerin üzerinde asılı olduğunu bulmak için sorunuzda yeterli kod yok. Kodunda tuhaf görünen bazı şeyler var. Örneğin, Proses sınıfında yerleşik olanları kullanmak yerine neden kendi hata ve çıkış okuma döngülerinizi başlatıyorsunuz? Şunun gibi: Hata ve çıkış zaman uyumsuz olaylar yana

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 
} 

ateş edilmez, bu shellProcess ile bir ömür boyu sorun olabileceğini beni inandıramaz. Daha fazla kod yazıyorsanız, daha iyi bir rehberlik sağlayabiliriz.

1

Bütün kodunuzu göremiyorum, ancak kolayca kullanımı Buhar nesneleri/yazma sizin yarattığı CMD Window komutlar göndermek için olabilir. ör .: Mesela yukarıdaki örnekte

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(); 

Komut istemi pencereden girilen gibi echo komutu alacaktır. Çıkışı göstermek için StreamReader nesnesini oluşturmanız ve işlemin StandardOutput'a atamanız gerekecek.

+0

Bu ekstra bagaj değil mi? – Gagan

İlgili konular