Externes Programm starten

  • VB.NET

Es gibt 10 Antworten in diesem Thema. Der letzte Beitrag () ist von Niko Ortner.

    Externes Programm starten

    Hallo Leute,

    ich versuche ein externes Programm zu starten. Dabei soll das abhängig vom sender mit unterschiedlichen Parametern aufgerufen werden (Ich habe das hier im Test mit einer Textbox). Funktioniert soweit auch, nur wie bekomme ich die Info beim Exit welcher Prozess beendet wurde um dann darauf reagieren zu können?

    Die Funktion muss mehrfach aufrufbar sein und das Programm soll weiter abgearbeitet werden also hilft mir prozess.wait leider nicht.

    Hat jemand eine Idee?

    PrivateSub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
    Dim ProcessProperties AsNewProcessStartInfo
    ProcessProperties.FileName =
    "notepad"
    ProcessProperties.Arguments = TextBox1.Text
    ProcessProperties.WindowStyle = ProcessWindowStyle.Maximized
    Dim myProcess AsProcess = Process.Start(ProcessProperties)
    myProcess.EnableRaisingEvents = TrueAddHandler myProcess.Exited, AddressOfMe.ProcessExited
    EndSub
    PrivateSub ProcessExited(ByVal sender AsObject, _
    ByVal e As System.EventArgs)
    '???
    EndSub
    Erstmal der Lesbarkeit halber:

    VB.NET-Quellcode

    1. Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
    2. Dim ProcessProperties As New ProcessStartInfo
    3. ProcessProperties.FileName = "notepad"
    4. ProcessProperties.Arguments = TextBox1.Text
    5. ProcessProperties.WindowStyle = ProcessWindowStyle.Maximized
    6. Dim myProcess As Process = Process.Start(ProcessProperties)
    7. myProcess.EnableRaisingEvents = True
    8. AddHandler myProcess.Exited, AddressOfMe.ProcessExited
    9. End Sub
    10. Private Sub ProcessExited(ByVal sender AsObject, ByVal e As System.EventArgs)
    11. '???
    12. End Sub


    Wäre das vielleicht durch einen Backgroundworker möglich, den du immer pro Prozess startest? Und indem du einfach in ner Schleife prüfst ob der Prozess noch gestartet ist?

    VB.NET-Quellcode

    1. Private Function CheckIfAProcessIsRunning(ByVal processname As String) As Boolean
    2. Return Process.GetProcessesByName(processname).Length > 0
    3. End Function


    Damit könntest ja prüfen ob der Prozess aktiv ist.

    Du könntest dir natürlich auch jeden Prozessnamen in nen Array speichern und dieses Array im Backgroundworker immer durchlaufen lassen und drauf reagieren wenn ein Programm aus dem Array (oder der List of String) nicht mehr aktiv ist.

    Ähnlich habe ich es bei dem Programm: hempel-tools.de/Hempel-Tools/Prozesswatch.html
    gemacht. Hier habe ich nen Start/Stop Button, welcher einen Backgroundworker startet.
    Dieser prüft dann ob ein Programm beendet wurde oder abgestürzt ist.
    Mittels + Button fülle ich Prozesse in eine Liste, welche ich im Backgroundworker immer prüfe.
    Es war einmal ein kleiner Bär... der wollte eine Geschichte hörn... Da erzählte ihm seine Mutti:
    Es war einmal ein kleiner Bär... der wollte eine Geschichte hörn... Da erzählte ihm seine Mutti:
    Es war einmal ein kleiner Bär... der wollte eine Geschichte hörn... Da erzählte ihm seine Mutti:
    ... Nun solltest es selber wissen. :'D

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „MemoAnMichSelbst“ ()

    Ist nicht weiter schwierig.
    Ist ja nen Control welches du im Designer einfach auf die Form ziehst...
    Mittels Doppelklick kommst du in die Stelle, in der du deklarierst was das Ding machen soll... Sprich... da kannst deine Schleife rein programmieren...
    Um nen Backgroundworker zu starten langt der Befehl:

    VB.NET-Quellcode

    1. BackgroundWorker.RunWorkerAsync()


    Zum Stoppen würd ich ne globale Variable hinterlegen die du per Buttonklick auf True setzt und in der Schleife (innerhalb des Backgroundworkers) immer prüfst.
    Bsp. du baust dir ne Variable

    VB.NET-Quellcode

    1. Friend stoppen as Boolean = True

    Diese setzt du beim Start des Workers auf False und sobald du ihn stoppen willst wieder auf True.
    Die interne Schleife ist dann einfach:

    VB.NET-Quellcode

    1. Do While stoppen = False
    Es war einmal ein kleiner Bär... der wollte eine Geschichte hörn... Da erzählte ihm seine Mutti:
    Es war einmal ein kleiner Bär... der wollte eine Geschichte hörn... Da erzählte ihm seine Mutti:
    Es war einmal ein kleiner Bär... der wollte eine Geschichte hörn... Da erzählte ihm seine Mutti:
    ... Nun solltest es selber wissen. :'D
    Mein Vorschlag:
    Den Process in eine Klasse packen, die instanzen der Klasse in eine Liste packen, und wenn der Prozess beendet wird, dann wird ein Event ausgelöst, das eine Referenz auf sich selbst ("sender") mit gibt, wodurch es möglich ist die Instanz der Klasse gezielt aus der Liste zu entfernen.

    VB.NET-Quellcode

    1. Dim AllProcesses As New List(Of ProcessInfo)
    2. Private Sub OpenProcessName() Handles TextBox_Path.Click
    3. Using OFD As New OpenFileDialog
    4. If OFD.ShowDialog = DialogResult.OK Then
    5. TextBox_Path.Text = OFD.FileName
    6. End If
    7. End Using
    8. End Sub
    9. Private Sub AddProcess() Handles Button_AddProcess.Click
    10. If System.IO.File.Exists(TextBox_Path.Text) Then
    11. Dim NewProcess As New ProcessInfo(New ProcessStartInfo() With {.FileName = TextBox_Path.Text, .WindowStyle = ProcessWindowStyle.Maximized})
    12. AddHandler NewProcess.ProcessExited, AddressOf ProcessExited
    13. AllProcesses.Add(NewProcess)
    14. ActualizeListBox()
    15. End If
    16. End Sub
    17. Private Sub ProcessExited(ByVal sender As ProcessInfo)
    18. AllProcesses.Remove(sender)
    19. Me.Invoke(Sub() ActualizeListBox()) 'Da diese Events in einem anderen Thread laufen muss das Ganze mit Invoke() in den GUI-Thread gebracht werden
    20. End Sub
    21. Private Sub ActualizeListBox()
    22. ListBox_AllProcesses.BeginUpdate() 'Unterdrückt das Neuzeichnen wärend dem Bearbeiten der Items
    23. ListBox_AllProcesses.Items.Clear()
    24. ListBox_AllProcesses.Items.AddRange(AllProcesses.ToArray)
    25. ListBox_AllProcesses.EndUpdate()
    26. End Sub
    27. Class ProcessInfo
    28. Implements IDisposable
    29. Public Event ProcessExited(ByVal sender As ProcessInfo)
    30. Dim WithEvents Process As Process
    31. Public Sub New(ByVal Info As ProcessStartInfo)
    32. Process = Process.Start(Info)
    33. Process.EnableRaisingEvents = True
    34. End Sub
    35. Private Sub OnProcessExited() Handles Process.Exited
    36. RaiseEvent ProcessExited(Me)
    37. Me.Dispose()
    38. End Sub
    39. Public Overrides Function ToString() As String
    40. Return Process.ProcessName & " - " & If(Process.HasExited, "Beendet", "Läuft")
    41. End Function
    42. #Region "IDisposable Support"
    43. Private disposedValue As Boolean ' So ermitteln Sie überflüssige Aufrufe
    44. ' IDisposable
    45. Protected Overridable Sub Dispose(ByVal disposing As Boolean)
    46. If Not Me.disposedValue Then
    47. If disposing Then
    48. ' TODO: Verwalteten Zustand löschen (verwaltete Objekte).
    49. Process.Dispose()
    50. Process = Nothing
    51. End If
    52. ' TODO: Nicht verwaltete Ressourcen (nicht verwaltete Objekte) freigeben und Finalize() unten überschreiben.
    53. ' TODO: Große Felder auf NULL festlegen.
    54. End If
    55. Me.disposedValue = True
    56. End Sub
    57. ' TODO: Finalize() nur überschreiben, wenn Dispose(ByVal disposing As Boolean) oben über Code zum Freigeben von nicht verwalteten Ressourcen verfügt.
    58. 'Protected Overrides Sub Finalize()
    59. ' ' Ändern Sie diesen Code nicht. Fügen Sie oben in Dispose(ByVal disposing As Boolean) Bereinigungscode ein.
    60. ' Dispose(False)
    61. ' MyBase.Finalize()
    62. 'End Sub
    63. ' Dieser Code wird von Visual Basic hinzugefügt, um das Dispose-Muster richtig zu implementieren.
    64. Public Sub Dispose() Implements IDisposable.Dispose
    65. ' Ändern Sie diesen Code nicht. Fügen Sie oben in Dispose(ByVal disposing As Boolean) Bereinigungscode ein.
    66. Dispose(True)
    67. GC.SuppressFinalize(Me)
    68. End Sub
    69. #End Region
    70. End Class

    Ein Apell an den Verstand: Nicht einfach C&P machen, sondern wenigstens versuchen zu verstehen, was da steht.


    Eine andere Möglichkeit:
    Die Prozesse selbst in die Liste packen, auf ein Event warten und dann alle Einträge entfernen, bei denen der Prozess beendet wurde.

    VB.NET-Quellcode

    1. Dim AllProcesses As New List(Of Process)
    2. Private Sub OpenProcessName() Handles TextBox_Path.Click
    3. Using OFD As New OpenFileDialog
    4. If OFD.ShowDialog = DialogResult.OK Then
    5. TextBox_Path.Text = OFD.FileName
    6. End If
    7. End Using
    8. End Sub
    9. Private Sub AddProcess() Handles Button_AddProcess.Click
    10. If System.IO.File.Exists(TextBox_Path.Text) Then
    11. Dim NewProcess As Process = Process.Start(New ProcessStartInfo() With {.FileName = TextBox_Path.Text, .WindowStyle = ProcessWindowStyle.Maximized})
    12. AddHandler NewProcess.Exited, AddressOf ProcessExited
    13. NewProcess.EnableRaisingEvents = True
    14. AllProcesses.Add(NewProcess)
    15. ActualizeListBox()
    16. End If
    17. End Sub
    18. Private Sub ProcessExited(ByVal sender As Object, ByVal e As EventArgs)
    19. For i As Integer = AllProcesses.Count - 1 To 0 Step -1
    20. If AllProcesses(i).HasExited Then
    21. AllProcesses(i).Dispose() 'Nicht vergessen!
    22. AllProcesses.RemoveAt(i)
    23. End If
    24. Next
    25. Me.Invoke(Sub() ActualizeListBox()) 'Da diese Events in einem anderen Thread laufen muss das Ganze mit Invoke() in den GUI-Thread gebracht werden
    26. End Sub
    27. Private Sub ActualizeListBox()
    28. ListBox_AllProcesses.BeginUpdate() 'Unterdrückt das Neuzeichnen wärend dem Bearbeiten der Items
    29. ListBox_AllProcesses.Items.Clear()
    30. 'Um eine schöne Darstellung zu erhalten wird nicht einfach Process.ToString angezeigt, sondern für jeden Prozess den Name und eine Information, ob er noch läuft
    31. ListBox_AllProcesses.Items.AddRange(Array.ConvertAll(AllProcesses.ToArray, Function(Item As Process) Item.ProcessName & " - " & If(Item.HasExited, "Beendet", "Läuft")))
    32. ListBox_AllProcesses.EndUpdate()
    33. End Sub
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils
    Was ja anwendungstechnisch so ziemlich das Selbe ist oO
    Bringt ja nicht einen Vorteil. Zumindest sehe ich keinen.
    Es war einmal ein kleiner Bär... der wollte eine Geschichte hörn... Da erzählte ihm seine Mutti:
    Es war einmal ein kleiner Bär... der wollte eine Geschichte hörn... Da erzählte ihm seine Mutti:
    Es war einmal ein kleiner Bär... der wollte eine Geschichte hörn... Da erzählte ihm seine Mutti:
    ... Nun solltest es selber wissen. :'D
    Neuer Thread oder neuer BGW. Wüsste jetzt Anwendertechnisch keinen wirklichen Vorteil oO
    Zumal er im Grunde ja nur einen braucht in dem er alle Prozesse prüft.
    Es war einmal ein kleiner Bär... der wollte eine Geschichte hörn... Da erzählte ihm seine Mutti:
    Es war einmal ein kleiner Bär... der wollte eine Geschichte hörn... Da erzählte ihm seine Mutti:
    Es war einmal ein kleiner Bär... der wollte eine Geschichte hörn... Da erzählte ihm seine Mutti:
    ... Nun solltest es selber wissen. :'D
    @Lehmann: Wir haben nicht umsonst Events, auf die man reagieren sollte.

    Ein gutes Beispiel, das ich von jemandem hier aus dem Forum habe:
    Wenn Du Pizza bestellst, dann rennst Du auch nicht alle 5 Sekunden zur Tür um zu sehen ob der Pizzamann schon da ist, sondern Du wartest, bis die Türklingel läutet.

    Verwende die Events. Das belastet den Prozessor nicht unnötig mit einer Endlosschleife.
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils