Process.Start in extra Thread

Thau

Mitglied
Hi,
ich versuche mit folgendem Sub ein programm zu starten

Code:
    Private Sub RunApp(ByVal Befehl As String, ByVal Parameter As String)
        Dim Run As Process = New Process

        Run.StartInfo.FileName = Befehl
        Run.StartInfo.Arguments = Parameter
        Run.StartInfo.UseShellExecute = False
        Run.StartInfo.RedirectStandardOutput = True
        Run.StartInfo.RedirectStandardError = True
        Run.StartInfo.RedirectStandardInput = True
        Run.StartInfo.CreateNoWindow = True
        Run.Start()

        TextBox1.Text += Run.StandardOutput.ReadToEnd() & vbCrLf
        TextBox1.Text += Run.StandardError.ReadToEnd() & vbCrLf
        TextBox1.SelectionStart = Len(TextBox1.Text)
        TextBox1.ScrollToCaret()
        TextBox1.Focus()
        Application.DoEvents()
        Run.WaitForExit()
    End Sub

Jetzt würde ich es gerne hinbekommen, das dieses Programm in einem Extra Thread läuft.

Ich weiß das man das mit Dim ExtraThread As New Thread(AddressOf RunApp)
macht. Jetzt bekomm ich nur immer folgende Meldung:
Meldung hat gesagt.:
Fehler bei der Überladungsauflösung, da keine zugreifbare "New" mit diesen Argumenten aufgerufen werden kann:
'Public Sub New(start As System.Threading.ParameterizedThreadStart)': Die Signatur der Private Sub RunApp(Befehl As String, Parameter As String)-Methode ist mit dem Delegaten "Delegate Sub ParameterizedThreadStart(obj As Object)" nicht kompatibel.
'Public Sub New(start As System.Threading.ThreadStart)': Die Signatur der Private Sub RunApp(Befehl As String, Parameter As String)-Methode ist mit dem Delegaten "Delegate Sub ThreadStart()" nicht kompatibel.
Ich hab zwar raus gefunden, das der Fehler daran liegt, das das Sub mehr als einen Parameter hat, aber es muss doch eine Möglichkeit geben, das das programm trotzdem in einem Extra Thread startet oder?
 
Hallo,

ich denke, einen Thread brauchst du dafür nicht zu erzeugen.
Schaue dir mal den Exited-Event der Process-Klasse an. Damit kannst du dich über die Beendigung des externen Programmes benachrichtigen lassen, ohne mit WaitForExit die aufrufende Methode zu blockieren.

Gruß
MCoder
 
@Masterclavat: Hat mir leider nicht so ganz geholfen, da in dem Beispiel mehrere Forms benutzt wurden, ich aber nur eine habe und auch nur eine Klasse.

@MCoder: Ich wollte das Programm in einem Extra Thread laufen lassen, weil bei Programmen die eine Weile im Hintergrund laufen, gleich die ganze Form für die Zeit einfriert und das wollte ich damit verhindern.
 
Ich hab den Sub jetzt mal so gändert:
Code:
    Private Sub RunApp(ByVal Befehl As String, ByVal Parameter As String)
        Dim Run As Process = New Process

        Run.StartInfo.FileName = Befehl
        Run.StartInfo.Arguments = Parameter
        Run.StartInfo.UseShellExecute = False
        Run.StartInfo.RedirectStandardOutput = True
        Run.StartInfo.RedirectStandardError = True
        Run.StartInfo.RedirectStandardInput = True
        Run.StartInfo.CreateNoWindow = True
        Run.Start()

        TextBox1.Text += Run.StandardOutput.ReadToEnd() & vbCrLf
        TextBox1.Text += Run.StandardError.ReadToEnd() & vbCrLf
        TextBox1.SelectionStart = Len(TextBox1.Text)
        TextBox1.ScrollToCaret()
        TextBox1.Focus()
        Application.DoEvents()
        'Run.WaitForExit()
        If (Run.HasExited) Then
            MessageBox.Show("Finished!")
        End If
    End Sub

Aber auch wenn ich das Run.WaitForExit() rausnehme oder nicht, das Programm friert trotzdem ein.
 
Hi

Debug doch mal und schau an welcher Stelle er "hängt".
Ich geh davon aus, dass das StandardOutput.ReadToEnd() und/oder StandardError.ReadToEnd() der Fall ist, da diese synchron laufen:
MSDN hat gesagt.:
Der umgeleitete StandardOutput-Stream kann synchron oder asynchron gelesen werden. Methoden wie Read, ReadLine und ReadToEnd führen synchrone Lesevorgänge im Ausgabestream des Prozesses aus. Diese synchronen Lesevorgänge werden erst beendet, wenn der zugeordnete Process Daten in den StandardOutput-Stream schreibt oder den Stream schließt.
Entweder du fragst die Daten nach Beenden des Prozesses ab (siehe Exited-Event) oder du machst das über die asynchonen Methoden Begin- und EndRead.
 
Natürlich.

Dein "ReadToEnd" blockiert.

ReadToEnd liest alles, bis der Stream geschlossen ist und das passiert halt erst, wenn dein Programm beendet ist.

Anstatt von Threads könntest einfach die asynchrone Lestemethode benutzen, um die Ausgaben des Programms aufzusammeln.

Hier siehst wie es geht.

WaitForExit darfst natürlich dennoch nicht verwenden. Das würde dein Programm auch einfrieren. Stattdessen abonniere einfach das Exited Event.

lg,..
 
Danke für die Hilfe. Ich hab mir mit der msdn Seite folgendes gebaut:
Code:
    Private Shared OutputString As StringBuilder = Nothing
    Private Shared numOutputLines As Integer = 0


    Private Sub RunApp(ByVal Befehl As String, ByVal Parameter As String)
        Dim Run As Process = New Process

        Run.StartInfo.FileName = Befehl
        Run.StartInfo.Arguments = Parameter
        Run.StartInfo.UseShellExecute = False
        Run.StartInfo.CreateNoWindow = True
        Run.StartInfo.RedirectStandardOutput = True
        Run.StartInfo.RedirectStandardError = True
        Run.StartInfo.RedirectStandardInput = True
        OutputString = New StringBuilder

        AddHandler Run.OutputDataReceived, AddressOf OutputStringHandler

        Run.Start()

        Run.BeginOutputReadLine()
        Run.BeginErrorReadLine()

        'TextBox1.Text &= Run.StandardOutput.ReadToEnd() & vbCrLf
        'TextBox1.Text &= Run.StandardError.ReadToEnd() & vbCrLf

        TextBox1.Text = OutputString.ToString

        TextBox1.SelectionStart = Len(TextBox1.Text)
        TextBox1.ScrollToCaret()
        TextBox1.Focus()
        Application.DoEvents()
        'Run.WaitForExit()
        If (Run.HasExited) Then
            TextBox1.Text &= "finished"
        End If
    End Sub

    Private Shared Sub OutputStringHandler(ByVal sendingProcess As Object, _
   ByVal outLine As DataReceivedEventArgs)

        ' Collect the sort command output.
        If Not String.IsNullOrEmpty(outLine.Data) Then
            numOutputLines += 1

            ' Add the text to the collected output.
            OutputString.Append(Environment.NewLine + "[" _
                         + numOutputLines.ToString() + "] - " _
                         + outLine.Data)
        End If
    End Sub

Aber ich bekomme trotzdem den Inhalt nicht und ich weiß auch nicht wofür das OutputStringHandler sein soll.
 
Diesen StringBuilder namens "OutputString" kannst bei dir weglassen, und im "OutputStringHandler" fügst du den Text einfach deiner TextBox an, dann sollts klappen.

"OutputStringHandler" ist der EventHandler für das Event welches gefeuert wird, wenn neue Daten vom Programm verfügbar sind.
 

Neue Beiträge

Zurück