2011-02-23 159 views
0

我正在使用在后台运行cmd的winform,异步地重定向输入和输出。等待命令完成

目前,winform迭代了一系列命令,通过StreamInter将StandardInput重定向到的每个cmd写入cmd。在写入下一行之前,如何强制循环等待当前命令在cmd中完成?

编辑:我拿出了我所有的实际项目代码,并用它替换了它,这是我试图做的简化版本,只包括我的项目中与我的问题相关的组件。

public partial class Form1 : Form 
{ 

    public delegate void WriteToConsoleMethod(string text); 
    Process _process; 

    string[] _commands = 
    { 
     "echo hello world", 
     "echo my name is T.K.", 
     "echo Here is a list of commands" 
    }; 
    public Form1() 
    { 
     InitializeComponent(); 
     ProcessStartInfo processStartInfo = new ProcessStartInfo("cmd") 
     { 
      RedirectStandardError = true, 
      RedirectStandardInput = true, 
      RedirectStandardOutput = true, 
      UseShellExecute = false, 
      CreateNoWindow = true 
     }; 

     _process = Process.Start(processStartInfo); 
     _process.OutputDataReceived += new DataReceivedEventHandler(new DataReceivedEventHandler(DataReceived_EventHandler)); 
     _process.ErrorDataReceived += new DataReceivedEventHandler(new DataReceivedEventHandler(DataReceived_EventHandler)); 
     _process.BeginErrorReadLine(); 
     _process.BeginOutputReadLine(); 
    } 

    private void DataReceived_EventHandler(object sender, DataReceivedEventArgs e) 
    { 
     IAsyncResult result = this.BeginInvoke(new WriteToConsoleMethod(writeToConsole), new object[] { e.Data + Environment.NewLine }); 
     this.EndInvoke(result); 
    } 

    private void writeToConsole(string output) 
    { 
     txtbxConsole.AppendText(output); 
    } 

    private void btnBegin_Click(object sender, EventArgs e) 
    { 
     foreach (string command in _commands) 
     { 
      _process.StandardInput.WriteLine(command); 
      // I want a way to pause here until the cmd has finished processing the command. 
     } 
    } 
} 
+0

你能发表一些代码吗? – JohnFx 2011-02-23 13:56:15

+0

好的 - 给我一分钟把它放在一起。 – 2011-02-23 14:07:23

+0

你可以发布run方法的代码吗? – sgmoore 2011-02-23 14:15:56

回答

1

我不认为有内置的支持的事情。然而,你可以把你自己的特殊命令,然后等到你看到这个输出例如, 是这样的:

const string Separator= "---Command Completed--\xE3\xE2\xE1\xE0\xE3"; 
    // Has to be something that won't occur in normal output. 

    volatile bool finished = false; 

    private void button1_Click(object sender, EventArgs e) 
    {   
     foreach (string command in _commands) 
      Run(command); 
    } 

    private void writeToConsole(string output) 
    { 
     if (output.IndexOf(Separator) >= 0) 
      finished = true; 
     else 
      richTextBox1.AppendText(output); 
    } 


    private void Run(string command) 
    { 
     finished = false; 
     _process.StandardInput.WriteLine(command); 
     _process.StandardInput.WriteLine("@echo " + Seperator); 
     while (!finished) 
     { 
      Application.DoEvents(); 
      System.Threading.Thread.Sleep(100); 
     } 
    } 

    private void Form1_FormClosing(object sender, FormClosingEventArgs e) 
    { 
     finished = true; 
    } 
+0

是的,如果我有一个字符串发生,当且仅当命令完成时,这将是一个很好的解决方案。但是,我不能指望知道我的命令会输出什么。但是,对于可以确定输出内容的情况,这是一个很好的解决方案。 – 2011-02-23 17:29:41

0

假设你正在使用的System.Diagnostics.Process,那么你可能需要像

ProcessStartInfo pi = new ProcessStartInfo(cmd);     
pi.Arguments = ... 
pi.WorkingDirectory = ... 
Process myProcess = Process.Start(pi);  
myProcess.WaitForExit(); 
+0

我正在使用System.Diagnositc.Process。不过,我不想等待退出。每次运行不同的命令时,我不希望_proc退出。我也编辑过,以包含我的流程初始化方法。 – 2011-02-23 15:01:30

0

我最终通过缠绕在命令提示符下我的互动成一个单独的类解决这个问题而不是保持一个提示的所有行动,我开始每个电话的另一个提示。然后我利用WaitForExit()来同步我的线程。

每次执行命令后,我都会写一个exit命令来关闭进程。我扫描输出的退出调用,当我找到一个,我使用该行的上下文来保存工作区,以便下一个命令的提示将从同一个工作目录。我还必须挂接一个DataRecievedEventHandler以在将EventHandler转发给winform之前解析出标题并退出调用。

关于此解决方案令我困扰的事情是,如果我正在运行的任何进程的输出打印出exit,那么输出扫描程序的行为就像发现原始出口一样。我采用了与sgmoore在他的回答中一样的解决方案 - 我在exit [UNIQUE STRING]中写下提示,并扫描输出结果,但我相信这远不是最佳做法。