问题
I've been struggling with this all week so I'm hoping the experts here can help me out. I have an executable that absolutely must be run from the command line with arguments. What I'm trying to do is instead of launching the command prompt window, I'd like to send the data to the rich text box on my form.
If I setup a batch file and run the batch file with the correct code (running it as a Process
), this works no problem. However, I'd like for the user to be able to enter their own arguments into a TextBox
instead of creating a batch file and referencing it.
I can only get this application to run correctly by using Call Shell. However, I read that you can't output the data to a RichTextBox
if you're using Call Shell and that it needs to be setup as a new Process
. I just can't seem to get this running as a Process
.
So the question is, is it possible to somehow output the Call Shell data to a RichTextBox
control, or is there a way to get this thing to run as a process? The Visual Basic code below will get it to run, but won't output to the RichTextBox
. I removed any code that I tried because every try was a failure.
This button will start the Process
, or if the Process
is running, it will kill it.
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
回答1:
It's quite possible using System.Diagnostics.Process.
The actual result depends on how that program actually works.
It might require some tests to get its output right.
This is a generic procedure you can use to test if your executable behaves in a standard way.
It's using tracert.exe
and ouputs its results in a RichTextBox
control.
Note that the Process.Start()
initialization uses the Process.SynchronizingObject() set to the RichTextBox
control Parent Form to avoid InvokeRequired
. But if you don't want to use a Synch object, Control.Invoke
is handled anyway, using MethodInvoker delegate.
To switch to your executable, subsitute the StartProcess()
method parameters as required.
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
Note:
If you need to terminate more that one running processes, you'll have to modify the code a bit more.
You could use a Class object to contain the Process Id, the Process Name (eventually) and a sequential value to maintain a reference to each process run.
Use a List(Of [Class])
for this.
You might also need to modify the StartProcess()
method to pass a Control reference (the Control where the different processes output their results).
The code, as it is, needs very few modifications to achieve this.
来源:https://stackoverflow.com/questions/51312990/how-to-output-shell-command-to-a-richtextbox-in-visual-basic