您無法以這種方式將命令發送到shell。 info.Arguments中的字符串是在命令行中提供給程序的參數。如果你想讓cmd.exe shell執行一系列命令然後退出,你必須提供/ c參數。如果您有多個要執行的命令,則必須將這些命令放入批處理文件中並執行該命令,或將它們用引號引起來,並用& &即info.Arguments = @"/c ""cd \ && dir""";
將它們分隔開。您從未返回的其他問題是,cmd.exe在缺少任何或適當參數的情況下執行時會默認以交互模式打開。/c選項告訴cmd.exe執行相關命令,然後退出。
此外,像Python和Perl這樣的解釋器有時會在從ProcessStartInfo直接啓動時出現奇怪的行爲。如果帶有perl.exe的info.Arguments = @"""MyPerlProgram.pl""";
不起作用,您可能會發現需要在cmd.exe中啓動它們才能獲得正常行爲,即info.Arguments = @"/c ""perl.exe ""MyPerlProgram.pl""""";
。
請參閱Cmd和ProcessStartInfo.Arguments Property。
要回答你的編輯3問題,你可能沒有正確掛鉤輸出。在調用Start之前,在ProcessOutputHandler具有類似public static void ProcessOutputHandler(object sendingProcess, DataReceivedEventArgs outLine)
的簽名之前,不要試圖掛鉤StreamReader的BaseStream,而要掛鉤OutputDataReceived事件this.shellProcess.OutputDataReceived += ProcessOutputHandler;
。在撥打開始後立即致電this.shellProcess.BeginOutputReadLine();
。該過程對於錯誤輸出也是類似的。有關更多詳細信息,請參見Process.BeginOutputReadLine Method和Process.BeginErrorReadLine Method。
如果您仍有問題,如果您只是嘗試process.StartInfo.Arguments = @"/c ""python.exe -c ""import sys; print 'Test.';""""";
,您會得到什麼?
此外,下面的代碼演示了大多數必要的理念,爲殼連通:
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。
編輯
根據您的意見,我已經修改了代碼互動提交工作。但是,有一個問題。在StandardError輸出中提供了python提示(>>>
),它不會回顯StandardInput。它也不會終止線路。這使得檢測提示變得困難並且由於process_ErrorDataReceived不會觸發而導致提示字符的一些亂序輸出,直到過程結束或者看到行結束爲止。
嗨傑米,請你提供一個可能有幫助的例子或鏈接嗎? – Gagan 2012-08-01 22:09:38
用cmd.exe的info.Arguments示例取消了回答,並添加了解釋爲什麼該進程永遠不會自行終止的解釋。 – JamieSee 2012-08-01 22:45:55
用編輯3的解決方案更新了答案。 – JamieSee 2012-08-14 17:14:12