我还猜想并非所有应用程序都正确使用 stderr 和 stdout,因此您在“控制台应用程序”中看到的内容可能没有提供您期望的信息。
如果没有更多重定向stderr,还可以让您查看它是否与语法相关并且应用程序正在抛出异常。
startInfo.RedirectStandardError = true;
我想补充一点,通过将其包装在一个类中,您可以与 cmd shell 交互,而不仅仅是运行和返回...如果您尝试静默自动化应用程序,这可能是您的方法想要...
我刚刚为一个使用 VB 的人编写了一个示例,语法可能很粗糙,因为我已经很多年没有启动 VB,但是你明白了它的要点并且应该能够很容易地在 C# 中复制。这是一个粗略的如何输入方法,而不是一段我称之为生产就绪的代码,教一个人钓鱼样本;)
#Region " Imports "
Imports System.Threading
Imports System.ComponentModel
#End Region
Namespace Common
Public Class CmdShell
#Region " Variables "
Private WithEvents ShellProcess As Process
#End Region
#Region " Events "
''' <summary>
''' Event indicating an asyc read of the command process's StdOut pipe has occured.
''' </summary>
Public Event DataReceived As EventHandler(Of CmdShellDataReceivedEventArgs)
#End Region
#Region " Public Methods "
Public Sub New()
ThreadPool.QueueUserWorkItem(AddressOf ShellLoop, Nothing)
Do Until Not ShellProcess Is Nothing : Loop
End Sub
''' <param name="Value">String value to write to the StdIn pipe of the command process, (CRLF not required).</param>
Public Sub Write(ByVal value As String)
ShellProcess.StandardInput.WriteLine(value)
End Sub
#End Region
#Region " Private Methods "
Private Sub ShellLoop(ByVal state As Object)
Try
Dim SI As New ProcessStartInfo("cmd.exe")
With SI
.Arguments = "/k"
.RedirectStandardInput = True
.RedirectStandardOutput = True
.RedirectStandardError = True
.UseShellExecute = False
.CreateNoWindow = True
.WorkingDirectory = Environ("windir")
End With
Try
ShellProcess = Process.Start(SI)
With ShellProcess
.BeginOutputReadLine()
.BeginErrorReadLine()
.WaitForExit()
End With
Catch ex As Exception
With ex
Trace.WriteLine(.Message)
Trace.WriteLine(.Source)
Trace.WriteLine(.StackTrace)
End With
End Try
Catch ex As Exception
With ex
Trace.WriteLine(.Message)
Trace.WriteLine(.Source)
Trace.WriteLine(.StackTrace)
End With
End Try
End Sub
Private Sub ShellProcess_ErrorDataReceived(ByVal sender As Object, ByVal e As System.Diagnostics.DataReceivedEventArgs) Handles ShellProcess.ErrorDataReceived
If Not e.Data Is Nothing Then RaiseEvent DataReceived(Me, New CmdShellDataReceivedEventArgs(e.Data))
End Sub
Private Sub ShellProcess_OutputDataReceived(ByVal sender As Object, ByVal e As System.Diagnostics.DataReceivedEventArgs) Handles ShellProcess.OutputDataReceived
If Not e.Data Is Nothing Then RaiseEvent DataReceived(Me, New CmdShellDataReceivedEventArgs(e.Data & Environment.NewLine))
End Sub
#End Region
End Class
<EditorBrowsable(EditorBrowsableState.Never)> _
Public Class CmdShellDataReceivedEventArgs : Inherits EventArgs
Private _Value As String
Public Sub New(ByVal value As String)
_Value = value
End Sub
Public ReadOnly Property Value() As String
Get
Return _Value
End Get
End Property
End Class
End Namespace
为了确保没有陷阱,我继续在 c# 中做了这件事
public class cmdShell
{
private Process shellProcess;
public delegate void onDataHandler(cmdShell sender, string e);
public event onDataHandler onData;
public cmdShell()
{
try
{
shellProcess = new Process();
ProcessStartInfo si = new ProcessStartInfo("cmd.exe");
si.Arguments = "/k";
si.RedirectStandardInput = true;
si.RedirectStandardOutput = true;
si.RedirectStandardError = true;
si.UseShellExecute = false;
si.CreateNoWindow = true;
si.WorkingDirectory = Environment.GetEnvironmentVariable("windir");
shellProcess.StartInfo = si;
shellProcess.OutputDataReceived += shellProcess_OutputDataReceived;
shellProcess.ErrorDataReceived += shellProcess_ErrorDataReceived;
shellProcess.Start();
shellProcess.BeginErrorReadLine();
shellProcess.BeginOutputReadLine();
}
catch (Exception ex)
{
Trace.WriteLine(ex.Message);
}
}
void shellProcess_ErrorDataReceived(object sender, DataReceivedEventArgs e)
{
doOnData(e.Data);
}
void shellProcess_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
doOnData(e.Data);
}
private void doOnData(string data)
{
if (onData != null) onData(this, data);
}
public void write(string data)
{
try
{
shellProcess.StandardInput.WriteLine(data);
}
catch (Exception ex)
{
Trace.WriteLine(ex.Message);
}
}
}
所以现在这样使用
cmdShell test = new cmdShell();
test.onData += test_onData;
test.write("ping 127.0.0.1");
这个就位
void test_onData(cmdShell sender, string e)
{
Trace.WriteLine(e);
}
您有一个完全交互式的 cmd 进程来写入和接收异步数据。
输出到窗口
C:\Windows>ping 127.0.0.1
Pinging 127.0.0.1 with 32 bytes of data:
Reply from 127.0.0.1: bytes=32 time<1ms TTL=128
Reply from 127.0.0.1: bytes=32 time<1ms TTL=128
Reply from 127.0.0.1: bytes=32 time<1ms TTL=128
Reply from 127.0.0.1: bytes=32 time<1ms TTL=128
Ping statistics for 127.0.0.1:
Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
Minimum = 0ms, Maximum = 0ms, Average = 0ms
咖啡,睡觉……哈哈
如果你真的想要约会...
cmdShell test = new cmdShell();
test.onData += test_onData;
test.write("date");
产量输出
C:\Windows>date
The current date is: Wed 10/08/2014
或
cmdShell test = new cmdShell();
test.onData += test_onData;
test.write("echo %date%");
产量输出
C:\Windows>echo %date%
Wed 10/08/2014
顺便说一句,如果你还没有真正使用过代码,这个方法会提供异步的数据,这意味着 as 程序输出它是交付给你的,所以如果你运行一个进程需要时间,例如 100 次 ping、traceroute 等……您可以在它们发生时看到它们,而不必等待它完成并返回。
您还可以在期间将命令传回应用程序,例如取消、响应和更改语法,或者根据第一次运行的结果简单地运行其他类似的东西。
基本上,您可以像在 cmd 窗口中输入一样对待它,并在那里接收反馈,将整个想法包装在一个正确的线程形式中(从其他线程更新 windows 控件时要小心),并且您将有一个模拟cmd提示符。