发送命令到CMD在C#中的提示 [英] Sending commands to cmd prompt in C#

查看:1229
本文介绍了发送命令到CMD在C#中的提示的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有关我实现我的工作是应该发送/工具之一检索cmd窗口的命令/业绩/。一切工作正常,但下面的用例没有做任何事情。看来,如果我的申请正在等待的东西(而不是显示的结果)

For one of my implementations I am working on a tool that is supposed to send/retrieve commands/results to/from the cmd window. Everything works fine but the Use case below fails to do anything. It seems as if my application is waiting for something (instead of displaying the result)

从我的工具,我浏览到蟒蛇文件夹。从Python文件夹我尝试推出python.exe,但在这一点上,我的编辑并不做任何事情。它只是不断的等待。

From my tool I navigate to the python folder . From the python folder I try to launch python.exe but at this point, my editor does not do anything. it simply keeps on waiting.

有关您的关照,我也在这里连接视频。它会更容易为你们明白我想说的。

For your kind consideration I am also linking the video here. It would be easier for you guys to understand what I am trying to say.

查看视频在这里(在YouTube上)

我还附上了code,我现在有。

I am also attaching the code that I currently have.

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

感谢您!

编辑:
启动蟒蛇只是一个例子。我需要使用其他正常的CMD命令行作为well.It将是很好,如果有人可以点我在做什么毛病code,我有或者我必须做的,为了达到同样的方法预期功能。

Launching python is just an example. I need to use the same method for other normal cmd line commands as well.It would be nice, if somebody can point what i am doing wrong with the code that I have or what I must do , in order to achieve the intended functionality.

编辑2:正常的CMD命令完美的工作。命令行工具,如蟒蛇,perl的不工作。

EDIT 2 : The normal cmd commands are working perfectly. The command line tools like python,perl are not working .

编辑3:所以我设法做到向前一丁点下杰米的建议。用户界面是不是挂了。但是当我访问蟒间preTER,跨preTER的输出仍然不是我的工具可见。任何建议为什么可能发生?

Edit 3 : So I managed to do move a wee bit forward following Jamie's suggestions. The ui is not "hanging" anymore. but when i access the python interpreter , the interpreter's output is still not visible in my tool. Any suggestions why that might be happening ?

推荐答案

您不能命令发送到外壳这种方式。在info.Arguments的字符串是提供给程序的命令行参数。如果你想CMD.EXE shell执行一系列命令,然后退出,你将不得不提供/ C参数。如果您有想要执行你要么必须把命令在批处理文件并执行,或将它们括在引号中,并与&放分隔多个命令;&放;,即 info.Arguments = @/ C,CD \\&放大器;&安培; DIR; 。你的另一个问题从来没有返回时,为它没有任何执行,或适当的,论点cmd.exe,在默认情况下交互模式打开。 / c选项告诉cmd.exe执行相关的命令,然后退出。

You cannot send commands to a shell this way. The string in info.Arguments is the arguments provided to the program on the command line. If you want the cmd.exe shell to execute a series of command and then quit you will have to provide the /c argument. If you have multiple commands that you want it to perform you will either have to put the commands in a batch file and execute that or enclose them in quotes and separate them with &&, i.e. info.Arguments = @"/c ""cd \ && dir""";. Your other issue with never returning is that cmd.exe opens in interactive mode by default when it is executed without any, or proper, arguments. The /c option tells cmd.exe to execute the relevant commands and then quit.

此外,除preters像Python和Perl当来自直接的ProcessStartInfo推出有时候怪异的行为。如果 info.Arguments = @MyPerlProgram.pl; 与perl.exe所在不起作用,你可能会发现有必要启动它们里面的cmd.exe获得正常的行为了出来,即 info.Arguments = @/ Cperl.exe所在,MyPerlProgram.pl;

Additionally, interpreters like python and perl sometimes have weird behaviors when launched directly from ProcessStartInfo. If info.Arguments = @"""MyPerlProgram.pl"""; with perl.exe doesn't work, you may find it necessary to launch them inside cmd.exe to get normal behavior out of them, i.e. info.Arguments = @"/c ""perl.exe ""MyPerlProgram.pl""""";.

请参阅 Cmd的和<一个href=\"http://msdn.microsoft.com/en-us/library/system.diagnostics.processstartinfo.arguments.aspx\">ProcessStartInfo.Arguments物业。

要回答你的修改3 的问题,你可能没有正确挂接到输出。而不是试图钩住的StreamReader的BaseStream,勾与 this.shellProcess.OutputDataReceived + = ProcessOutputHandler的OutputDataReceived事件; 你打电话的地方开始ProcessOutputHandler有一个像<$ C $签名前C>公共静态无效ProcessOutputHandler(对象sendingProcess,DataReceivedEventArgs轮廓)。呼叫后,立即启动,请拨打 this.shellProcess.BeginOutputReadLine(); 。该过程是对误差输出中也相似。见<一href=\"http://msdn.microsoft.com/en-us/library/system.diagnostics.process.beginoutputreadline\">Process.BeginOutputReadLine方法和<一个href=\"http://msdn.microsoft.com/en-us/library/system.diagnostics.process.beginerrorreadline\">Process.BeginErrorReadLine方法了解更多详情。

To answer your Edit 3 problem, you're probably not correctly hooking into the outputs. Instead of trying to hook the StreamReader's BaseStream, hook the OutputDataReceived event with this.shellProcess.OutputDataReceived += ProcessOutputHandler; before you call Start where ProcessOutputHandler has a signature like public static void ProcessOutputHandler(object sendingProcess, DataReceivedEventArgs outLine). Immediately after calling Start, call this.shellProcess.BeginOutputReadLine();. The process is similar for the error ouput as well. See Process.BeginOutputReadLine Method and Process.BeginErrorReadLine Method for more details.

如果您仍然有一个问题,你是什么,如果你只是尝试 process.StartInfo.Arguments = @/ Cpython.exe -c进口SYS;打印测试。 ;?

If you still have a problem, what do you get if you just try process.StartInfo.Arguments = @"/c ""python.exe -c ""import sys; print 'Test.';""""";?

此外,code以下演示大多壳通信所需的概念:

Also, the code below demonstrates most of the necessary concepts for shell communication:

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

您可能会导致您的问题线程问题。我已经做了一些这方面的进一步工作,并能得到一个文本框在窗体上具有以下code更新:

You may have threading issues causing your problems. I've done some further work with this and was able to get a textbox on a form to update with the following code:

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

我创建了一个表格,并添加一个文本框,并在表格下面code:

I created a form and added a textbox and the following code in the form:

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

有一点需要注意的是,如果Form1_Load事件未完成,调用将挂起,直到它。如果你长时间运行code在一个事件你要么需要异步调用使用的BeginInvoke,或定期调用的DoEvents长时间运行code。

One thing to note is that if the Form1_Load event doesn't complete, Invoke will hang until it does. If you have long-running code in an event you'll either need to invoke asynchronously using BeginInvoke, or periodically call DoEvents in your long-running code.

修改

根据您的评论,我已经修改了code互动提交工作。然而,有一个问题。 Python提示符(&GT;&GT;&GT; )设在StandardError的输出,并没有呼应StandardInput。它也不会终止该行。这使得检测提示困难而导致一些了提示字符由于process_ErrorDataReceived不触发直到进程结束或线端看到顺序输出的。

Per your comment, I've modified the code to work with interactive submissions. There is, however, a problem. The python prompt (>>>) is provided on the StandardError output and it does not echo the StandardInput. It also does not terminate the line. This makes detecting a prompt difficult and causes some out of order output of the prompt characters due to the process_ErrorDataReceived not firing until either the process ends or a line end is seen.

这篇关于发送命令到CMD在C#中的提示的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆