首页 > 解决方案 > 如何在 Visual Basic 中将 Shell 命令输出到 RichTextBox

问题描述

我整个星期都在努力解决这个问题,所以我希望这里的专家可以帮助我。我有一个绝对必须从带有参数的命令行运行的可执行文件。我想要做的不是启动命令提示符窗口,而是将数据发送到表单上的富文本框。

如果我设置一个批处理文件并使用正确的代码运行批处理文件(将其作为 a 运行Process),这没有问题。但是,我希望用户能够将自己的参数输入 aTextBox而不是创建批处理文件并引用它。

我只能通过使用 Call Shell 让这个应用程序正确运行。RichTextBox但是,我读到如果您使用 Call Shell,则无法将数据输出到 a并且需要将其设置为新的Process. 我似乎无法让它作为Process.

所以问题是,是否有可能以某种方式将 Call Shell 数据输出到RichTextBox控件,或者有没有办法让这个东西作为一个进程运行?下面的 Visual Basic 代码将使其运行,但不会输出到RichTextBox. 我删除了我尝试过的所有代码,因为每次尝试都是失败的。

此按钮将启动Process,或者如果Process正在运行,它将终止它。

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    Dim exeargs As String = txtExeArgs.Text
    Dim p1() As Process
    Dim strCommand As String = "executable.exe " & exeargs & ""
    p1 = Process.GetProcessesByName("executable")
    Dim exepath As String = IO.Path.GetDirectoryName(Me.txtExeLocation.Text)

    If p1.Count <= 0 Then

        RichTextBox1.Clear()

        Call Shell("cmd.exe /c cd /d " & exepath & " & " & strCommand, 0)

    Else
        Dim killprocess = System.Diagnostics.Process.GetProcesses().Where((Function(p) p.ProcessName = "executable"))
        For Each p As Process In killprocess
            p.Kill()
        Next
        RichTextBox1.Clear()
    End If
End Sub

标签: vb.netshellcommand-linerichtextbox

解决方案


使用System.Diagnostics.Process很有可能。
实际结果取决于该程序的实际工作方式。
它可能需要一些测试才能使其输出正确。

这是一个通用过程,您可以使用它来测试您的可执行文件是否以标准方式运行。它在控件中
使用tracert.exe并输出其结果。RichTextBox

请注意,Process.Start()初始化使用Process.SynchronizingObject()设置为RichTextBox控件父窗体来避免InvokeRequired。但是,如果您不想使用 Synch 对象,Control.Invoke则无论如何都要使用MethodInvoker委托来处理。

要切换到您的可执行文件,请StartProcess()根据需要替换方法参数。

Imports System.Diagnostics
Imports System.IO

Private CurrentProcessID As Integer = -1

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    StartProcess("C:\Windows\System32\tracert.exe", "stackoverflow.com")
End Sub

Private Sub StartProcess(FileName As String, Arguments As String)

    Dim MyStartInfo As New ProcessStartInfo() With {
        .FileName = FileName,
        .Arguments = Arguments,
        .WorkingDirectory = Path.GetDirectoryName(FileName),
        .RedirectStandardError = True,
        .RedirectStandardOutput = True,
        .UseShellExecute = False,
        .CreateNoWindow = True
    }

    Dim MyProcess As Process = New Process() With {
        .StartInfo = MyStartInfo,
        .EnableRaisingEvents = True,
        ' Setting a SynchronizingObject, we don't need to BeginInvoke. 
        ' I leave it there anyway, in case there's no SynchronizingObject to set
        ' BeginInvoke can be used with or without a synchronization context.
        .SynchronizingObject = Me
    }

    MyProcess.Start()
    MyProcess.BeginErrorReadLine()
    MyProcess.BeginOutputReadLine()

    CurrentProcessID = MyProcess.Id

    AddHandler MyProcess.OutputDataReceived,
        Sub(sender As Object, e As DataReceivedEventArgs)
            If e.Data IsNot Nothing Then
                BeginInvoke(New MethodInvoker(
                Sub()
                    RichTextBox1.AppendText(e.Data + Environment.NewLine)
                    RichTextBox1.ScrollToCaret()
                End Sub))
            End If
        End Sub

    AddHandler MyProcess.ErrorDataReceived,
        Sub(sender As Object, e As DataReceivedEventArgs)
            If e.Data IsNot Nothing Then
                BeginInvoke(New MethodInvoker(
                Sub()
                    RichTextBox1.AppendText(e.Data + Environment.NewLine)
                    RichTextBox1.ScrollToCaret()
                End Sub))
            End If
        End Sub

    AddHandler MyProcess.Exited,
        Sub(source As Object, ev As EventArgs)
            MyProcess.Close()
            If MyProcess IsNot Nothing Then
                MyProcess.Dispose()
            End If
        End Sub
End Sub


注意
如果您需要终止多个正在运行的进程,则必须对代码进行更多修改。
您可以使用 Class 对象来包含进程 ID、进程名称(最终)和一个顺序值,以维护对每个进程运行的引用。为此
使用 a 。 您可能还需要修改方法以传递 Control 引用(不同进程输出其结果的 Control)。 代码实际上只需要很少的修改就可以实现这一点。List(Of [Class])
StartProcess()


推荐阅读