等待命令完成

发布于 2024-10-19 08:35:53 字数 1913 浏览 4 评论 0原文

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

目前,winform 迭代一系列命令,通过 StandardInput 重定向到的 StreamWriter 将每个命令写入 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.
        }
    }
}

I am working with a winform that runs a cmd in the background, redirecting input and output asynchronously.

Currently, the winform iterating through an array of commands, writing each to the cmd via the StreamWriter the StandardInput is redirected to. How can I force the loop to wait until the present command is complete in the cmd before writing the next line in?

EDIT: I took out all of my actual project code, and replaced it with this, a stripped down version of what I'm trying to do, only including components of my project relevant to my question.

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.
        }
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

冷心人i 2024-10-26 08:35:53

我认为没有任何内置的东西可以支持这一点。但是,您可以发送自己的特殊命令,然后等到您在输出中看到此命令,例如,
类似的东西:

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

I don't think there is anything built-in that will support that. However you could send your own special command and then wait until you see this in the output for example ,
something like :

    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;
    }
再可℃爱ぅ一点好了 2024-10-26 08:35:53

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

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

Assuming you are using System.Diagnostics.Process, then you probably need something like

ProcessStartInfo pi = new ProcessStartInfo(cmd);                
pi.Arguments = ...
pi.WorkingDirectory = ...
Process myProcess = Process.Start(pi);      
myProcess.WaitForExit();
混浊又暗下来 2024-10-26 08:35:53

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

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

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

I ended up solving this problem by wrapping my interaction with the command prompt into a separate class and instead of maintaining one prompt for all of the actions, I started up another prompt for each call. Then I take advantage of WaitForExit() to synchronize my threads.

After each command, I write in an exit command to close the process. I scan the output for exit calls, and when I find one, I use the context of that line to save the workspace so that the prompt for the next command will be made from the same working directory. I also had to hook up a DataRecievedEventHandler to parse out the header and exit calls before forwarding the EventHandlers to the winform.

The thing that's nagging me about this solution is that if the output of whatever process I'm running prints out exit, output scanner will behave as though it found the original exit. I employed the same solution sgmoore had in his answer - I write in exit [UNIQUE STRING] to the prompt, and scan the output for that, but I'm sure that's far from best practice.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文