Mehrere Consolenprozesse starten, auf alle warten und einzeln auswerten

  • VB.NET

Es gibt 6 Antworten in diesem Thema. Der letzte Beitrag () ist von XBrainBug.

    Mehrere Consolenprozesse starten, auf alle warten und einzeln auswerten

    Hallo,

    ich suche mich schon seit Tagen durch das Internet und Foren aber finde keine passende Lösung für mein Problem, obwohl ich denke so schwer kann es nicht sein.
    Ich habe eine Array mit Benutzernamen und PC-Namen und ein Feld mit Text. Jetzt soll ein Befehl an jeden Benutzer des Array eine Nachricht schicken mit "MSG.exe" und auswerten ob derjenige die Meldung weg geklickt hat. An sich klappt das versenden und auswerten soweit ABER ich kriege es nicht hin, das gewartet wird, bis alle die Nachricht geschlossen haben oder das System die Meldung automatisch nach 60 Sekunden schließt. Der Consolenprozess wartet ab bis der Benutzer die Meldung mit "OK" weg klickt oder schließt sie von alleine nach 60 Sek.
    Ich dachte mit Task.Waitall wartet er bis alles fertig ist und dann macht er weiter aber er wartet auf nichts. Habe auch schon den ausführenden Code in eine eigene Async Sub geschrieben und die über Task.run aufgerufen aber das selbe Problem. Entweder wartet er jede einzelne For each Schleife ab oder er arbeitet alles komplett ab stoppt nicht bei Task.WaitAll().

    Hier ein Ausschnitt von meinem Code

    VB.NET-Quellcode

    1. Private Async Sub Button5_Click(sender As Object, e As EventArgs) Handles Button5.Click
    2. Dim selectedRowCount As Integer = DataGridView1.Rows.GetRowCount(DataGridViewElementStates.Selected)
    3. Dim Computer, User, Nachricht As String
    4. Dim i, n, anzahl As Integer
    5. n = 0
    6. anzahl = selectedRowCount
    7. abgeschlossen = 0
    8. If selectedRowCount > 0 Then
    9. Await Task.Run(async Sub()
    10. For i = 0 To selectedRowCount - 1
    11. Using ConsoleProcess As New Process
    12. ConsoleProcess.StartInfo.CreateNoWindow = True
    13. ConsoleProcess.StartInfo.FileName = "cmd.exe"
    14. ConsoleProcess.StartInfo.RedirectStandardOutput = True
    15. ConsoleProcess.StartInfo.RedirectStandardInput = True
    16. ConsoleProcess.StartInfo.UseShellExecute = False
    17. ConsoleProcess.Start()
    18. Start = Now
    19. Await ConsoleProcess.StandardInput.WriteLineAsync("c:\tools\msg.exe /w /v " & User & " /SERVER:" & Computer & " ""Von: " & GlobalVariables.Username & " | " & Nachricht & """")
    20. Await ConsoleProcess.StandardInput.WriteLineAsync("exit")
    21. ConsoleProcess.WaitForExit()
    22. Ende = Now
    23. End Using
    24. End Sub)
    25. Next i
    26. Task.WaitAll
    @XBrainBug Eine Console ist wie das Word, was neben dem VisualSudio läuft, nur dass die Console und dein Programm verkabelt sind.
    Mit Async Await wirst Du das Problem so nicht lösen können.
    Probiere mal, eine Batch-Datei zu schreiben, die dies richtig macht.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Eigentlich läuft es schon, es klappt auch mit await sync, wenn ich die Tasks zähle und dann eine While schleife einbaue die wartet bis alle abgearbeitet sind.

    VB.NET-Quellcode

    1. While abgeschlossen < anzahl
    2. Threading.Thread.Sleep(500)
    3. End While


    ​Aber da ist das Programm nicht benutzbar bis das while abgearbeitet ist.

    ​Wie gesagt, das ganze auswerten usw. ist kein Problem, nur das warten auf alle Tasks ohne das die GUI einfriert oder jeder Task einzeln abläuft, klappt nicht.
    @XBrainBug Dann lasse doch das Warten auf Beendigung in einem separaten Thread laufen, und wenn alles feddich ict, sendest Du der GUI ein entsprechendes Event.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    @ThuCommix
    ​Es ist genau das Gegenteil, Task.Waitall wird vollkommen ignoriert. Ich habe so gut wie alle Kombinationen ausprobiert mit async und ohne etc. Entweder wartet der Threat bis der Mitarbeiter die Messsagebox geschlossen hat, bevor die nächste For each Schleife abgearbeitet wird oder er macht was er soll und arbeitet alle "zugleich" ab aber wartet zum Schluss nicht bis alle beendet wurden.

    @RodFromGermany
    Gute Idee, hatte ich gestern schon mal drüber nachgedacht aber irgendwann sollte man auch mal Feierabend machen! Werde ich mal testen, ggfs. könnte ich ja auch ein Label etc. Asynchron mit dem Daten befüllen lassen, bisher habe ich das immer mit einer MsgBox zum Schluss gemacht, die das fertige Ergebnis anzeigt.
    OK, ich habs etwas umgebaut, soweit Funktioniert es.
    Alle Nachrichten werden sofort rausgeschickt und wenn der Threat beendet wird, schreibe ich das Ergebnis in ein Label, klappt wunderbar.....musste zwar noch ein Invoke einbauen wegen den Threats aber das war lösbar.

    Zur Erklärung, falls es jemand benötigt:
    - Rufe Benutzername, PC-Name aus einem DataGridView ab
    - Rufe mit Task.run die Sub Prozess1 auf
    - Dort lasse ich asynchron für jeden Benutzer eine Nachricht mit MSG.exe verschicken und warte auf das Schließen der Console. Wenn die Console erst nach 60 Sekunden geschlossen wird, wurde die Nachricht nicht weg geklickt, das System hat sie selbst entfernt
    - Das Ergebnis kommt in ein Label sobald der Threat beendet wurde
    - und fertig

    VB.NET-Quellcode

    1. Private Async Sub Button5_Click(sender As Object, e As EventArgs) Handles Button5.Click
    2. Dim selectedRowCount As Integer = DataGridView1.Rows.GetRowCount(DataGridViewElementStates.Selected)
    3. Dim Computer, User, Nachricht As String
    4. If selectedRowCount > 0 Then
    5. For i = 0 To selectedRowCount - 1
    6. Await Task.Run(Sub()
    7. User = Me.DataGridView1.SelectedRows(i).Cells(0).Value
    8. Computer = Me.DataGridView1.SelectedRows(i).Cells(1).Value
    9. Nachricht = Replace(Me.TextBox_Nachricht.Text, Chr(34), Chr(34) & Chr(34))
    10. Process1(User, Computer, Nachricht)
    11. End Sub)
    12. Next i
    13. Else
    14. MessageBox.Show("Es wurden keine Zeile/n ausgewählt!")
    15. End If
    16. End Sub
    17. Public Delegate Sub ChangeLabelText(ByVal caption As String)
    18. Private Async Sub Process1(username As String, computer As String, Nachricht As String)
    19. Dim Start, Ende As DateTime
    20. Dim Befehl As String
    21. Using ConsoleProcess As New Process
    22. ConsoleProcess.StartInfo.CreateNoWindow = True
    23. ConsoleProcess.StartInfo.FileName = "cmd.exe"
    24. ConsoleProcess.StartInfo.RedirectStandardOutput = True
    25. ConsoleProcess.StartInfo.RedirectStandardInput = True
    26. ConsoleProcess.StartInfo.UseShellExecute = False
    27. ConsoleProcess.Start()
    28. Start = Now
    29. Befehl = "c:\tools\msg.exe /w /v " & username & " /SERVER:" & computer & " ""Von: " & GlobalVariables.Username & " | " & Nachricht & """" & vbCrLf
    30. Dim sendBytes As [Byte]() = System.Text.Encoding.GetEncoding(437).GetBytes(Befehl)
    31. Await ConsoleProcess.StandardInput.BaseStream.WriteAsync(sendBytes, 0, sendBytes.Length)
    32. Await ConsoleProcess.StandardInput.WriteLineAsync("exit")
    33. ConsoleProcess.WaitForExit()
    34. Ende = Now
    35. End Using
    36. If DateDiff(DateInterval.Second, Start, Ende) >= 60 Then
    37. Me.Invoke(New ChangeLabelText(AddressOf Meldung), username & ": Nicht bestätigt")
    38. Else
    39. Me.Invoke(New ChangeLabelText(AddressOf Meldung), username & ": Bestätigt")
    40. End If
    41. End Sub
    42. Private Sub Meldung(ByVal Text As String)
    43. Me.Label_Meldung.Text += Text & vbCrLf
    44. End Sub

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