在另一个问题中解释了一些问题后,我继续编写了一个模拟Windows命令提示符的应用程序。每个命令都由一个调用“CMD.exe / C [command]”的Process对象执行,并将其标准输出/错误重定向到Winform。
一切顺利但是当我执行某些命令时表单崩溃,例如“time”或“wmic”请求某些用户交互(RedirectStandardInput为TRUE)。如何解决此问题使光标等待输入(如经典提示)?
这是代码
Process cmdProcess = new Process();
cmdProcess.StartInfo.FileName = "CMD.exe";
cmdProcess.StartInfo.Arguments = "/C " + command;
cmdProcess.StartInfo.WorkingDirectory = this.workingDir;
cmdProcess.StartInfo.CreateNoWindow = true;
cmdProcess.StartInfo.UseShellExecute = false;
cmdProcess.StartInfo.RedirectStandardOutput = true;
cmdProcess.StartInfo.StandardOutputEncoding = Encoding.Default;
cmdProcess.StartInfo.RedirectStandardError = true;
cmdProcess.StartInfo.StandardErrorEncoding = Encoding.Default;
//cmdProcess.StartInfo.RedirectStandardInput = true;
cmdProcess.Start();
StreamReader outputR = cmdProcess.StandardOutput;
StreamReader errorR = cmdProcess.StandardError;
//StreamWriter inputW = cmdProcess.StandardInput;
string output = outputR.ReadToEnd();
string error = errorR.ReadToEnd();
if (output.Length > 0)
this.textArea.AppendText(Environment.NewLine + output);
else if (error.Length > 0)
this.textArea.AppendErrorText(Environment.NewLine + error);
我评论了启用输入重定向的所有部分,现在输出,例如,“time”命令不会询问任何用户输入并立即返回。显然我不喜欢这种行为;)
C:\Users\Alessandro\Progetti\CMDProject\CMDProject\bin\Debug>time
Ora corrente: 19:32:17,55
Immettere nuova ora:
C:\Users\Alessandro\Progetti\CMDProject\CMDProject\bin\Debug>
答案 0 :(得分:1)
我过去做了类似的事情,看看我的代码,它看起来不像你设置了callbascks,尝试这个,将我的命令变成你想要的,希望这会有所帮助:如果你开始另一个线程确保第一个是关闭的,正如我的代码所示......
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
using System.Threading;
using System.Globalization;
namespace VSSWriterTest
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public class VSSCommands
{
public string VSS_VSSExecutable = "vssadmin";
public string VSS_VSSListWriters = " list writers";
}
private void Form1_Load(object sender, EventArgs e)
{
//close handler
this.FormClosing+=new FormClosingEventHandler(Form1_FormClosing);
}
private void Form1_FormClosing(object sender, EventArgs e)
{
}
//my thread and process vars
private Process m_Process;
private Thread m_OutputThread;
private Thread m_ErrorThread;
private string m_TextToAdd;
//basic writer command line stuff
public class WriterStats
{
public string WriterName = "Writer Name";
public string WriterTD = "Writer Id";
public string WriterInstanceId = "Writer Instance Id";
public string WriterState = "State";
public string WriterLastError = "Last error";
public string NoError = "No error";
}
private void StartVSSDiagnostics()
{
try
{
this.rtbVSSList.Clear();
iErrorCount = 0;
iWriterCount = 0;
this.txtErrors.Clear();
//start cmd prompt, then write command statement to console screen
if ((StartVSSDiagnosticsThreads()))
{
VSSCommands ServiceCall = new VSSCommands();
string msg = ServiceCall.VSS_VSSExecutable + ServiceCall.VSS_VSSListWriters;
VSSStreamInput(msg);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "EVAS Backup and Restore");
}
}
private void VSSStreamInput(string Text)
{
try
{
if (Text != string.Empty)
{
m_Process.StandardInput.WriteLine(Text);
m_Process.StandardInput.Flush();
}
}
catch (Exception ex)
{
}
}
private bool StartVSSDiagnosticsThreads()
{
try
{
//close threads if open
CloseThreads();
//start new cmd prompt thread
m_Process = new Process();
{
m_Process.StartInfo.FileName = "cmd";
m_Process.StartInfo.UseShellExecute = false;
m_Process.StartInfo.CreateNoWindow = true;
m_Process.StartInfo.RedirectStandardOutput = true;
m_Process.StartInfo.RedirectStandardError = true;
m_Process.StartInfo.RedirectStandardInput = true;
}
m_Process.Start();
//create the call backs
m_OutputThread = new Thread(StreamOutput);
m_OutputThread.IsBackground = true;
m_OutputThread.Start();
m_ErrorThread = new Thread(StreamError);
m_ErrorThread.IsBackground = true;
m_ErrorThread.Start();
return true;
}
catch (Exception ex)
{
return false;
}
}
//this stream is feedback from the command prompt, its a delegate thats on a seperate thread other than this UI
private void StreamOutput()
{
try
{
string Line = m_Process.StandardOutput.ReadLine();
while (Line.Length >= 0)
{
if (Line.Length > 0)
{
ConsoleMessage(ConvertFromOem(Line));
}
Line = m_Process.StandardOutput.ReadLine();
}
}
catch
{
//ConsoleMessage(String.Format("""{0}"" Error!", m_Process.StartInfo.FileName))
}
}
//convert text encoding to readable characters
private string ConvertFromOem(string Text)
{
try
{
return Encoding.GetEncoding(CultureInfo.InstalledUICulture.TextInfo.OEMCodePage).GetString(Encoding.Default.GetBytes(Text));
}
catch (Exception ex)
{
return string.Empty;
}
}
//stream error callback
private void StreamError()
{
try
{
string Line = m_Process.StandardError.ReadLine();
while (Line.Length >= 0)
{
Line = m_Process.StandardError.ReadLine();
if (Line.Length > 0)
{
ConsoleMessage(Line, true);
}
}
}
catch
{
//ConsoleMessage(String.Format("""{0}"" Error!", m_Process.StartInfo.FileName))
}
}
//actual delegate that invokes the main thread
private void ConsoleMessage(string Text, bool err = false)
{
try
{
if (err)
{
m_TextToAdd = "ERROR: " + Text;
}
else
{
m_TextToAdd = Text;
}
this.Invoke((MethodInvoker)this.RaiseConsoleTextEvent);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
//raise text event, new text arrived from console
private void RaiseConsoleTextEvent()
{
try
{
VSSMessages(m_TextToAdd);
}
catch (Exception ex)
{
}
}
//my message filter, what i want displayed on my UI, i parse microsoft logo and garbage to display results only
private int iErrorCount = 0;
private int iWriterCount = 0;
private void VSSMessages(string e)
{
WriterStats IWriter = new WriterStats();
if ((e.ToUpper().Contains(IWriter.WriterInstanceId.ToUpper()) | e.ToUpper().Contains(IWriter.WriterLastError.ToUpper()) |
e.ToUpper().Contains(IWriter.WriterName.ToUpper()) | e.ToUpper().Contains(IWriter.WriterState.ToUpper()) |
e.ToUpper().Contains(IWriter.WriterTD.ToUpper())))
{
if ((e.ToUpper().Contains(IWriter.WriterName.ToUpper())))
{
iWriterCount += 1;
this.rtbVSSList.AppendText("Writer (" + iWriterCount.ToString() + ") " + e + Environment.NewLine);
}
else
{
this.rtbVSSList.AppendText(e + Environment.NewLine);
}
if ((e.ToUpper().Contains(IWriter.WriterLastError)))
{
if ((e.ToUpper().Contains(IWriter.NoError)))
{
iErrorCount += 1;
this.txtErrors.ForeColor = Color.Red;
}
}
this.txtErrors.Text = iErrorCount.ToString() + " Errors found in " + iWriterCount.ToString() + " system writers.";
if ((e.ToUpper().Contains(IWriter.WriterLastError.ToUpper())))
{
this.rtbVSSList.AppendText(Environment.NewLine);
}
Application.DoEvents();
}
}
//close any open threads, dont want run away threads!
private void CloseThreads()
{
try
{
if (((m_OutputThread != null)))
{
if ((m_OutputThread.IsAlive))
{
m_OutputThread.Abort();
}
}
if (((m_ErrorThread != null)))
{
if ((m_ErrorThread.IsAlive))
{
m_ErrorThread.Abort();
}
}
}
catch (Exception ex)
{
}
}
private void btnRun_Click(object sender, EventArgs e)
{
//begin
StartVSSDiagnostics();
}
}
}