将命令发送到C#中的cmd提示符
本文关键字:中的 cmd 提示符 命令 | 更新日期: 2024-09-23 13:25:39
对于我的一个实现,我正在开发一个工具,该工具应该向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);
}
谢谢!
编辑:启动python只是一个例子。我也需要对其他普通的cmd行命令使用相同的方法。如果有人能指出我在代码上做错了什么,或者我必须做什么,以实现预期的功能,那就太好了。
编辑2:正常的cmd命令运行良好。像python、perl这样的命令行工具不起作用。
编辑3:所以我按照杰米的建议向前推进了一点。ui不再"挂起"。但是当我访问python解释器时,解释器的输出在我的工具中仍然不可见。为什么会发生这种情况,有什么建议吗?
您不能以这种方式向shell发送命令。信息中的字符串。Arguments是在命令行上提供给程序的参数。如果希望cmd.exe shell执行一系列命令然后退出,则必须提供/c参数。如果您有多个要执行的命令,则必须将这些命令放在批处理文件中并执行,或者将它们括在引号中并用&;,即CCD_ 1。不返回的另一个问题是,cmd.exe在没有任何参数或正确参数的情况下执行时,默认情况下会以交互模式打开。/c选项告诉cmd.exe执行相关命令,然后退出。
此外,当直接从ProcessStartInfo启动时,像python和perl这样的解释器有时会有奇怪的行为。如果带有perl.exe的info.Arguments = @"""MyPerlProgram.pl""";
不起作用,您可能会发现有必要在cmd.exe中启动它们,以使它们具有正常行为,即info.Arguments = @"/c ""perl.exe ""MyPerlProgram.pl""""";
。
请参阅Cmd和ProcessStartInfo.Arguments属性。
要回答Edit 3问题,您可能没有正确连接到输出。与其尝试挂接StreamReader的BaseStream,不如在调用Start之前用this.shellProcess.OutputDataReceived += ProcessOutputHandler;
挂接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);
}
可能是线程问题导致了您的问题。我已经对此做了一些进一步的工作,并能够在表单上获得一个文本框来更新以下代码:
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();
}
}
}
}
我创建了一个表单,并在表单中添加了一个文本框和以下代码:
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事件没有完成,Invoke将挂起,直到完成为止。如果事件中有长时间运行的代码,则需要使用BeginInvoke异步调用,或者在长时间运行代码中定期调用DoEvents。
编辑
根据您的评论,我已经修改了代码以使用交互式提交。然而,存在一个问题。python提示符(>>>
)是在StandardError输出上提供的,它不回显StandardInput。它也不会终止线路。这使得检测提示变得困难,并且由于process_ErrorDataReceived直到进程结束或看到行结束才触发,导致提示字符的输出出现一些无序。
您的问题中没有足够的代码来确定您的应用程序到底挂在什么上。您的代码中有些东西看起来很奇怪。例如,为什么要启动自己的错误和输出读取循环,而不是使用Process类中内置的循环?像这样:
var shellProcess = System.Diagnostics.Process.Start(info);
shellProcess.EnableRaisingEvents = true;
shellProcess.Exited += ProcessExited;
shellProcess.OutputDataReceived += ShellProcess_OutputDataReceived;
shellProcess.ErrorDataReceived += ShellProcess_ErrorDataReceived;
shellProcess.BeginOutputReadLine();
shellProcess.BeginErrorReadLine();
void ShellProcess_ErrorDataReceived(object sender, DataReceivedEventArgs e)
{
// Do Something
}
void ShellProcess_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
// Do Something
}
由于您的错误和输出异步事件没有触发,这让我相信shellProcess可能存在生存期问题。如果您发布更多的代码,我们可以提供更好的指导。
我看不到您的所有代码,但您可以轻松地使用Steam对象向您创建的CMD窗口写入/发送命令。例如:
StreamWriter inputStream = shellProcess.StandardInput;
//send command to cmd prompt and wait for command to execute with thread sleep
inputStream.WriteLine("echo "CMD just received input");
inputStream.Flush();
例如,在上面的示例中,命令提示符将接收echo
命令,就像在窗口中输入一样。要显示输出,您必须创建info.Arguments = @"/c ""cd ' && dir""";
0对象并将其分配给进程的StandardOutput
。