在C#中向cmd提示符发送命令

Gag*_*gan 8 c# cmd winforms

对于我的一个实现,我正在研究一个应该向cmd窗口发送/检索命令/结果的工具.一切正常,但下面的用例没有做任何事情.好像我的应用程序正在等待某事(而不是显示结果)

从我的工具我导航到python文件夹.从python文件夹我尝试启动python.exe但此时,我的编辑器没有做任何事情.它只是在等待.

为了您的善意考虑,我也在这里链接视频.你们会更容易理解我想说的话.

在此处观看视频(在youtube上)

我还附上了我目前拥有的代码.

            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);
    }
Run Code Online (Sandbox Code Playgroud)

谢谢 !

编辑:启动python只是一个例子.我需要对其他普通的cmd行命令使用相同的方法.如果有人可以指出我所做的代码或我必须做的事情,我会做的很好,以实现预期的功能.

编辑2:正常的cmd命令工作正常.像python,perl这样的命令行工具不起作用.

编辑3:所以我设法在Jamie的建议之后向前移动了一点点.ui不再"悬挂"了.但是当我访问python解释器时,解释器的输出仍然在我的工具中不可见.有什么建议可能会发生吗?

Jam*_*See 17

您不能以这种方式向shell发送命令.info.Arguments中的字符串是在命令行上提供给程序的参数.如果希望cmd.exe shell执行一系列命令然后退出,则必须提供/ c参数.如果您希望它执行多个命令,则必须将命令放在批处理文件中并执行该命令或将它们用引号括起来并用&&分隔它们,即info.Arguments = @"/c ""cd \ && dir""";.您永远不会返回的另一个问题是cmd.exe在没有任何或适当的参数的情况下执行时默认以交互模式打开./ c选项告诉cmd.exe执行相关命令然后退出.

另外,直接从ProcessStartInfo启动时,python和perl等解释器有时会产生奇怪的行为.如果info.Arguments = @"""MyPerlProgram.pl""";使用perl.exe不起作用,您可能会发现有必要在cmd.exe中启动它们以获得正常行为,即info.Arguments = @"/c ""perl.exe ""MyPerlProgram.pl""""";.

请参阅CmdProcessStartInfo.Arguments属性.

要回答编辑3问题,您可能没有正确地连接到输出.而不是尝试挂钩StreamReader的BaseStream,this.shellProcess.OutputDataReceived += ProcessOutputHandler;在调用Start之前挂钩OutputDataReceived事件,其中ProcessOutputHandler具有类似的签名public static void ProcessOutputHandler(object sendingProcess, DataReceivedEventArgs outLine).在致电Start后立即致电this.shellProcess.BeginOutputReadLine();.该过程也类似于错误输出.有关更多详细信息,请参阅Process.BeginOutputReadLine方法Process.BeginErrorReadLine方法.

如果你还有问题,如果你试试,你会得到什么process.StartInfo.Arguments = @"/c ""python.exe -c ""import sys; print 'Test.';""""";

此外,下面的代码演示了shell通信的大多数必要概念:

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);
}
Run Code Online (Sandbox Code Playgroud)

您可能遇到导致问题的线程问题.我已经做了一些进一步的工作,并能够使用以下代码更新表单上的文本框:

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();
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我创建了一个表单,并在表单中添加了一个文本框和以下代码:

    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));
    }
Run Code Online (Sandbox Code Playgroud)

需要注意的一点是,如果Form1_Load事件没有完成,Invoke将挂起,直到它完成.如果在事件中有长时间运行的代码,则需要使用BeginInvoke异步调用,或者在长时间运行的代码中定期调用DoEvents.

编辑

根据您的评论,我修改了代码以使用交互式提交.然而,存在一个问题.>>>在StandardError输出上提供了python prompt(),它不会回显StandardInput.它也不会终止该行.这使得检测提示很困难并且由于process_ErrorDataReceived没有触发而导致一些无序输出的提示字符,直到进程结束或看到行结束.