2014-10-08 183 views
1

我想编写一个c#代码来执行一些命令提示符行,并将结果存储到c#中的全局变量中,以用于c#中其他代码部分的进一步处理。c#执行命令行如命令提示符?

我买了一个设备,我安装了它的驱动程序。我获取数据的唯一方法是在命令提示符下使用命令行。没有可用的API。但是,我想在c#中这样做,这就是为什么我有麻烦。

我有一些代码,它不能出于某种原因。请注意,我使用参数input =“date”仅用于说明目的。我的工作没有使用“日期”,而是使用一些参数来获取数据。

static void Main(string[] args) 
{ 
    System.Diagnostics.Process process = new System.Diagnostics.Process(); 
    System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo(); 
    startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden; 
    // the cmd program 
    startInfo.FileName = "cmd.exe"; 
    // set my arguments. date is just a dummy example. the real work isn't use date. 
    startInfo.Arguments = "date"; 
    startInfo.RedirectStandardOutput = true; 
    startInfo.UseShellExecute = false; 
    process.StartInfo = startInfo; 
    process.Start(); 
    // capture what is generated in command prompt 
    var output = process.StandardOutput.ReadToEnd(); 
    // write output to console 
    Console.WriteLine(output); 
    process.WaitForExit(); 

    Console.Read(); 
} 

任何帮助表示赞赏。

+5

'这就是为什么我有麻烦'什么麻烦? “它不起作用”不是对问题的描述。它有什么作用?崩溃?给出错误?沦为奇点?什么都不做?你期望它做什么? – 2014-10-08 15:09:14

+0

你的问题可能是'date'本身就会提示你输入一个新的日期(从命令行尝试它)。试着用'date/T'来输出日期,而不要求你给它任何输入。或者,您可能只需在标准输入中输入“enter”即可。 – 2014-10-08 15:12:00

回答

1

您需要使用/ c日期才能使cmd启动日期。

static void Main(string[] args) 
{ 
    System.Diagnostics.Process process = new System.Diagnostics.Process(); 
    System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo(); 
    startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden; 
    // the cmd program 
    startInfo.FileName = "cmd.exe"; 
    // set my arguments. date is just a dummy example. the real work isn't use date. 
    startInfo.Arguments = "/c date"; 
    startInfo.RedirectStandardOutput = true; 
    startInfo.UseShellExecute = false; 
    process.StartInfo = startInfo; 
    process.Start(); 
    // capture what is generated in command prompt 
    var output = process.StandardOutput.ReadToEnd(); 
    // write output to console 
    Console.WriteLine(output); 
    process.WaitForExit(); 

    Console.Read(); 
} 

使用cmd.exe启动其他程序时,flags/c和/ k是你的朋友。/c用于执行程序,然后退出CMD。/k用于执行程序,然后使CMD运行。

+0

在'date'的情况下,您还需要'date'的'/ T'标志,否则您需要将'StandardInput'和'WriteLine'重定向到它。 – 2014-10-08 15:25:09

+0

谢谢。但代码仍然没有给出日期。它是空的。 – CB4 2014-10-08 15:47:20

+0

实际上它的工作原理。日期可能有问题。我试过ipconfig,它提供的数据。做得好。 – CB4 2014-10-08 15:53:56

2

我也猜测并非所有的应用程序都正确使用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 

顺便说一句,如果你还没有实际使用的代码呢,这个方法给出数据的异步,意义作为程序输出它被交付给你,所以如果你运行一个需要花费时间的进程,比如100个ping,traceroute等......你看到它们发生时,不必等待它完成并返回。

此外,您可以在期间将命令传递回应用程序,与取消,响应并更改语法或仅根据第一次运行的结果运行其他类似的东西。基本上你可以像对待你在cmd窗口中输入一样对待它,然后在那里接收反馈,将整个思考包装在一个正确的线程形式中(小心从其他线程更新Windows控件时),并且你将拥有一个模拟cmd提示符。

+0

非常感谢您的回答!!!)))))这非常非常有用太棒了!我有一个小问题:如何使用您的工具从命令输出如“python.exe”? – neo 2016-12-07 14:14:28

+0

只要python在你的路径声明中,你应该可以像使用cmd提示符一样使用它。你想启动python并与它进行交互吗?或者你想自动化一个命令到python并查看输出?我无法从我的位置进行测试,但是如果输出到stderr和stdout,您应该可以用python替换cmd(或者如果不在路径中,则为python可执行文件的完整路径),我必须进行测试才能确定。我已经编写了几个应用程序,用这种方式自动化用CLR安装的.NET编译器。 – Sabre 2016-12-09 02:28:47

+0

我想通过cmd.exe自动化使用python.exe,但我遇到了问题。我无法得到python标准输出和stderror(((它看起来像我重定向到我的应用程序和python无法让他们自己的输出和错误。如果我运行与python.exe而不是cmd.exe进程,这种行为重复。我认为,与流重定向有关的问题。 – neo 2016-12-09 06:57:07

相关问题