等待命令完成

时间:2011-02-23 13:52:55

标签: c# winforms cmd

我正在使用在后台运行cmd的winform,异步重定向输入和输出。

目前,winform迭代一系列命令,通过StreamWriter将每个命令写入cmd,将StandardInput重定向到。如何强制循环等到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.
        }
    }
}

3 个答案:

答案 0 :(得分: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;
    }

答案 1 :(得分:0)

假设您正在使用System.Diagnostics.Process,那么您可能需要类似

的内容
ProcessStartInfo pi = new ProcessStartInfo(cmd);                
pi.Arguments = ...
pi.WorkingDirectory = ...
Process myProcess = Process.Start(pi);      
myProcess.WaitForExit();

答案 2 :(得分:0)

我最终解决了这个问题,将我与命令提示符的交互包装到一个单独的类中,而不是为所有操作维护一个提示,我为每个调用启动了另一个提示。然后我利用WaitForExit()来同步我的线程。

在每个命令之后,我用exit命令写入关闭进程。我扫描输出以进行退出调用,当我找到一个时,我使用该行的上下文来保存工作空间,以便从同一个工作目录提示下一个命令。在将EventHandlers转发给winform之前,我还必须连接一个DataRecievedEventHandler来解析头和退出调用。

关于这个解决方案让我烦恼的是,如果我正在运行的任何进程的输出打印出exit,输出扫描程序将表现得好像它找到了原始出口。我使用了sgmoore在他的答案中使用的相同解决方案 - 我在exit [UNIQUE STRING]写入提示,并扫描输出,但我确信这远非最佳实践。