用C#编写的cmd.exe样式应用程序

时间:2010-08-10 12:45:29

标签: c#

我试图从任何基于DOS的应用程序中获取结果,实际上让C#像操作用户一样操作它。

我可以让它执行命令,然后显示输出。问题是知道输出何时结束!例如,如果我开始/运行“cmd.exe”,键入“D:”,然后“cd D:\”,然后“树”,它在D驱动器上输出我的文件夹结构,然后允许我输入我的下一个命令(仅 后,它已完成打印列表)。

但是我无法在代码中找到方法让它意识到它已经完成,并且应该允许下一个命令(基本上当cmd.exe开始闪烁光标时)。

        public Process p = null;

    private void Form1_Load(object sender, System.EventArgs e)
    {
        ProcessStartInfo procStarter = new ProcessStartInfo("cmd.exe");
        procStarter.RedirectStandardOutput = true;
        procStarter.RedirectStandardInput = true;
        procStarter.UseShellExecute = false;
        procStarter.CreateNoWindow = true;
        p = Process.Start(procStarter);
    }

    private void Form1_Closing(object sender, System.ComponentModel.CancelEventArgs e)
    {
        p.Close();
    }

    private void btnSend_Click(object sender, System.EventArgs e)
    {
        p.StandardInput.WriteLine("D:");
        p.StandardInput.WriteLine(@"cd D:\");
        txtOutput.Text = SendCommand(txtInput.Text);
    }

    private string SendCommand(string cmd)
    {
        p.StandardInput.WriteLine(cmd);
        return p.StandardOutput.ReadToEnd();
    }

在SendCommand(string cmd)中,如果我按照上面的代码运行p.StandardOutput.ReadToEnd(),它会永远挂起,大概等待应用程序关闭?

如果我遍历p.StandardOutput.ReadLine(),它会显示所有文本(包括闪烁光标之前的“D:\>”,但它没有意识到它结束了,再次调用ReadLine,并以熟悉的方式挂起到ReadToEnd。如果当前行以“>”结尾,则一个肮脏的解决方法是将其视为响应的结束,但是如果一行在任何地方结束,那么它就会分崩离析回应。

我尝试逐个字符循环,并且最后没有发送特殊字符。

有什么想法吗?

注意:我的最终目标是提供一个轻型库,我可以用它来执行任何DOS可执行文件(可能需要传递给它的几个类型命令,而不仅仅是打开时通过命令行传递的一个关闭参数),解析结果使用正则表达式模板返回,并返回提取的结果。我想如果我能在windows应用程序中有效地重新实现cmd.exe,那么就可以使用这样的库。

谢谢, 利

5 个答案:

答案 0 :(得分:2)

我怀疑你的方法不起作用。当您运行的命令或是否已完成时,cmd.exe不会通过StandardOutput与您通信。 (我应该指出,这并不能阻止你运行多个命令。你可能只是发送命令行而不是需要等待它完成。)

也许更合适的方法可能根本不使用cmd.exe。而是使用Process.Start()来运行每个单独的命令。然后你可以使用StandardOutput.ReadToEnd(),它将在完成过程后结束,你可以运行下一个过程。

答案 1 :(得分:1)

我同意Timwi,但看看下面的内容是否有帮助

        ProcessStartInfo procStarter = new ProcessStartInfo("cmd.exe");
        procStarter.RedirectStandardOutput = true;
        procStarter.RedirectStandardInput = true;
        procStarter.UseShellExecute = false;
        procStarter.CreateNoWindow = true;
        procStarter.WorkingDirectory = @"D:\";
        procStarter.Arguments = "/C dir";
        Process p = Process.Start(procStarter);
        string output = p.StandardOutput.ReadToEnd();
一旦完成工作,

/ cm命令行到cmd.exe将终止cmd.exe。您还可以使用p.Exited(退出事件)来了解它何时发生。

但是它不会保持cmd.exe始终运行。但你真的需要让它继续运行吗?

答案 2 :(得分:0)

如果您正在寻找'如何等待产生的进程终止',那么Process.WaitForExit应该是什么诀窍。 您可以为每个“命令”生成一个新的shell。

答案 3 :(得分:0)

大约一年前,我为Windows编写了一个telnet服务器,允许远程用户针对cmd.exe发出命令。也许您可以将它作为自己项目的起点。

答案 4 :(得分:0)

通过读取输出异步,我已经使这个工作(几乎像你描述的那样):

    public Process p = null;

    private void Send_Click(object sender, System.EventArgs e)
    {

        p.StandardInput.WriteLine("D:");
        p.StandardInput.WriteLine(@"cd D:\");
        p.StandardInput.WriteLine(txtInput.Text);
    }

    private void Form1_Load_1(object sender, EventArgs e)
    {
        ProcessStartInfo procStarter = new ProcessStartInfo("cmd.exe");
        procStarter.RedirectStandardOutput = true;
        procStarter.RedirectStandardInput = true;
        procStarter.UseShellExecute = false;
        procStarter.CreateNoWindow = true;

        p = Process.Start(procStarter);

        p.OutputDataReceived += new DataReceivedEventHandler(p_OutputDataReceived);
        p.BeginOutputReadLine();

    }

    void p_OutputDataReceived(object sender, DataReceivedEventArgs e)
    {
        addTextToOutput(e.Data);
    }

    private void addTextToOutput(string text)
    {
        if (txtOutput.InvokeRequired)
        {
            addTextCallback cb = new addTextCallback(addTextToOutput);
            this.Invoke(cb, new Object[] { text });
        }
        else
        {
            txtOutput.Text += text+ System.Environment.NewLine;
        }
    }

    delegate void addTextCallback(String text);

    private void Form1_FormClosing(object sender, FormClosingEventArgs e)
    {
        p.Close();
    }