CMD auslesen und weiterverarbeiten

  • VB.NET

Es gibt 18 Antworten in diesem Thema. Der letzte Beitrag () ist von RodFromGermany.

    CMD auslesen und weiterverarbeiten

    Hallo zusammen,

    ich habe ein kleines vb.net Programm geschrieben, in dem ich mit process.start eine cmd + Programm starte.
    Es handelt sich um ein Auswertungsprogramm was in der cmd dann läuft, was einige Stunden dauern kann.

    Jetzt würde ich gerne alle 60 Sekunden die CMD auslesen und den Inhalt in eine Textbox eintragen.
    Sobald ein bestimmtes Wort in der Textbox dann vorkommt, würde ich eine Messagebox auslösen.

    Geht sowas? Wichtig ist, dass in einem bestimmten Zeitinterval (bspw. 60 Sekunden) die Textbox aktualisiert wird
    und die CMD weiterhin ganz normal sichtbar bleibt.

    Danke und LG
    Simone

    Eierlikörchen schrieb:

    Jetzt würde ich gerne alle 60 Sekunden die CMD auslesen und den Inhalt in eine Textbox eintragen.
    So funktioniert das nicht.
    Du hast hier eine Master-Slave-Situation, die Du erst mal für Dich verstehen und uns erklären musst, wenn wir Dir helfen sollen.
    Der Master tut was er will/soll, insbesondere wann er will/soll, der Slave wird vom Master angestoßen und tut dann das, was er tun muss.
    Der Takt (alle 60 Sekunden) wird dabei immer vom Master vorgegeben.

    Möglichkeit 1:
    Das Auswertungsprogramm (in der cmd gestartet) ist Master, Dein kleines vb.net Programm mit TextBox ist Slave.
    Wenn der Master ein Signal/Event/Was auch immer sendet, wird das vom Slave aufgefangen und der text angezeigt.
    Im Takt eines Timers oder abhängig vom Rechenfortschritt sendet das Auswertungsprogramm ein Signal.
    Mit den 60 Sekunden ist das möglicherweise nicht sehr präzise realisierbar.
    Allerdings ist das mit den Mitteln der Process-Klasse machbar.

    Möglichkeit 2:
    Dein kleines vb.net Programm mit TextBox ist Master, Das Auswertungsprogramm (in der cmd gestartet) ist Slave.
    Im "präzisen" 60-Sekunden-Takt sendet Dein kleines vb.net Programm mit TextBox ein was auch immer an das Auswertungsprogramm,
    worauf hin dieses die anzuzeigenden Daten bereitstellt.
    Ein solches Szenario mit der Process-Klasse zu bauen ist suboptimal.

    Frage:
    Verfügst Du über die Quellen dieses Auswertungsprogramms?
    Wenn ja, könnte man eine Client-Server-Architektur via TCP implementieren (Pipes), da ist Dein Problem relativ einfach zu lösen.
    Wenn nein: Gig uns deutlich mehr Informationen.
    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!
    Hallo Ihr beiden,

    erstmal Danke für Eure Antworten. Mit meinen spärlichen VB-Kenntnissen habe ich jetzt folgenden Code
    zusammengeschnipselt:

    Quellcode

    1. Dim oProcess As New Process()
    2. Dim oStartInfo As New ProcessStartInfo("cmd.exe", "/k " & TextBox6.Text)
    3. oStartInfo.UseShellExecute = False
    4. oStartInfo.RedirectStandardOutput = True
    5. oProcess.StartInfo = oStartInfo
    6. oProcess.Start()
    7. Dim sOutput As String
    8. Using oStreamReader As System.IO.StreamReader = oProcess.StandardOutput
    9. sOutput = oStreamReader.ReadToEnd()
    10. End Using
    11. TextBox7.Text = sOutput


    Eigentlich ist es genau das was ich möchte, aber es gibt jetzt zwei Probleme:
    1) Das CMD-Fenster öffnet sich, aber ich sehe nicht was passiert. Es läuft im Hintergrund ab. Welche Parameter
    muss ich angeben, damit die CMD "normal" angezeigt wird?
    2) Die Übertragung der Ergebnisse aus der CMD wird erst in die Textbox7 importiert, wenn ich die CMD schliesse.
    Gibt es einen Parameter, der laufend die CMD Ereignisse in die Textbox7 schreibt (also den Streamreader "live" mitlesen?)

    Lieben Dank für Eure Geduld
    Simone
    @Eierlikörchen Ich hab mal hier ein kleines Projekt zusammengebastelt
    Form mit zwei Buttons, einer CheckBox und einer TextBox:
    Button1 erstellt eine Console und listet den Inhalt des Verzeichnisses C:\Temp auf.
    Button2 startet ein Notepad.
    CheckBox1 entscheidet, ob die Console sichtbar sein soll oder nicht.
    In der TextBox1 werden die Ausgaben der Console ausgegeben.
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Public Class Form1
    2. Private WithEvents Cmd As Process
    3. Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    4. If Cmd Is Nothing OrElse Cmd.HasExited Then
    5. Cmd = New Process()
    6. Cmd.StartInfo.ErrorDialog = True
    7. Cmd.StartInfo.UseShellExecute = False
    8. Cmd.StartInfo.RedirectStandardInput = True
    9. Cmd.StartInfo.RedirectStandardOutput = True
    10. Cmd.StartInfo.RedirectStandardError = True
    11. Cmd.StartInfo.FileName = "cmd.exe"
    12. Cmd.StartInfo.CreateNoWindow = CheckBox1.Checked
    13. Cmd.StartInfo.StandardOutputEncoding = System.Text.Encoding.Default
    14. Cmd.Start()
    15. Cmd.BeginOutputReadLine()
    16. End If
    17. Cmd.StandardInput.WriteLine("cd C:\Temp")
    18. Cmd.StandardInput.WriteLine("dir ")
    19. End Sub
    20. Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
    21. If Cmd Is Nothing OrElse Cmd.HasExited Then
    22. Me.TextBox1.AppendText("Bitte erst Button1 drücken" & Environment.NewLine)
    23. Return
    24. End If
    25. Cmd.StandardInput.WriteLine("Notepad.exe")
    26. End Sub
    27. Private Sub cmdHandler(ByVal sendingProcess As Object, ByVal outLine As DataReceivedEventArgs) Handles Cmd.OutputDataReceived
    28. If Not String.IsNullOrEmpty(outLine.Data) Then
    29. Me.Invoke(Sub() Me.TextBox1.AppendText(Environment.NewLine & outLine.Data))
    30. End If
    31. End Sub
    32. Private Sub Form1_FormClosing(ByVal sender As System.Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles MyBase.FormClosing
    33. Try
    34. If Cmd IsNot Nothing Then
    35. Cmd.StandardInput.Flush()
    36. Cmd.StandardInput.Close()
    37. Cmd.CancelOutputRead()
    38. Cmd.Close()
    39. End If
    40. Catch
    41. End Try
    42. End Sub
    43. End Class
    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!
    Super, vielen Dank!! :)
    Das bringt mich schon ein ganzes Stück weiter ans Ziel.

    Wenn die Checkbox nicht gecheckt ist, dann startet die CMD und der Output geht in die Textbox > perfekt.
    Ist es auch möglich das beides gleichzeitig geht? Also die CMD zeigt die Abläufe "normal" an und gleichzeitig
    ein Output in die Textbox?

    Vielen Dank schonmal
    Simone

    Eierlikörchen schrieb:

    Also die CMD zeigt die Abläufe "normal" an und gleichzeitig ein Output in die Textbox?
    Meines Wissens nein, da der Output Stream nur zu einem Ziel umgeleitet werden kann.
    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!
    Ich hab ein wenig mit den RedirectStandard-Dingensen gespielt, ohne die geht sozusagen gar nix, da kann man cmd auch vom System aus starten.
    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!
    Eine Idee:
    Es gibt ein Programm tee.
    Das kommt aus Unix, gibt's aber auch für Windows.
    Das kann die Ausgabe auf zwei Kanäle ausgeben.
    Du pipest die CMD-Ausgabe auf tee.
    Die tee-Ausgaben legst du auf StandardOutput und StandardError.
    Dann siehst du die Daten über RedirectStandardOutput in deinem Programm.
    Und über StandardError auf deinem CMD-Fenster.
    --
    If Not Program.isWorking Then Code.Debug Else Code.DoNotTouch
    --
    Vielen Dank nochmal für Eure Unterstützung für eine VB-Neulinginne :)

    Vielleicht gibt es für mein Ziel auch eine andere Möglichkeit die einfacher ist, daher mein kleines Projekt kurz
    zuammengefasst:

    Das Analyseprogramm kann mehrere Tage oder Wochen dauern. Irgendwann sagt das Programm in der CMD "Done!".
    Sobald dieses Kommando kommt, möchte ich gerne eine Email aus VB versenden. Die Berechnungsschritte in der CMD will
    ich aber live verfolgen, daher ist es wichtig, dass die CMD die Fortschritte auch anzeigt.

    Daher ist es vielleicht gar nicht nötig mit dem Streamreader sämtlichen Output umzuleiten. Es würde auch reichen, wenn alle 60 Sekunden
    eine Copy der CMD-Ausgaben in eine Textbox oder String zu kopieren .... ala "Send-Keys".
    Aber Senk-Keys ist sehr fehleranfällig, richtig?

    Gibt es in vb.net eine Möglichkeit nach dem Motto ... aktiviere alle 60 Sekunde die CMD...mache einen STRG+C
    und füge es mit STRG+V in eine Textbox ein?

    Vielen, vielen Dank vorab für Eure Überlegungen.
    Simone
    SendKeys ist so fehleranfällig, dass mans wohl als unbrauchbar bezeichnen muss.

    Aber bastel dir doch selbst ein ConsoleFenster.
    Dann leiteste den Process-Output auf deinen Stream um, und zeigst den im eigenen Consolefenster an. Und da kannste ja auch reagieren, wenn was bestimmtes ankommt.

    Eierlikörchen schrieb:

    Das Analyseprogramm
    Hast Du davon die Quellen oder ist das ein gekauftes Dienst-Programm?
    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!
    Es ist ein gekauftes Programm. Aber mir ist gerade aufgefallen, dass das Programm eine Datei erzeugt, wenn es fertig ist.
    Dann könnte ich doch mein Vorhaben dahingehend ändern, dass ich nicht den Stream abfange, sondern überwache wann die
    Datei erzeugt wird, oder?

    Ich habe gerade mal gegooglet und Filewatcher gefunden. Wie kann man Filewatcher am einfachsten einsetzen?
    Überwacht Filewatcher ständig, ob bspw. die xyz.txt zwischenzeitlich erstellt wurde oder muss ich einen loop
    einbauen?

    Danke und schönen Sonntag
    Simone
    @Eierlikörchen Jou, das geht mit einem FileSystemWatcher:
    docs.microsoft.com/de-de/dotne…ystemwatcher?view=net-5.0
    Die Sprache (VB) kannst Du Dir oben rechts einstellen.
    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!
    Habe es jetzt alles irgendwie hingebogen und stehe vor dem nächsten Problem :-))

    Quellcode

    1. m_fsw = New IO.FileSystemWatcher(Application.StartupPath & "\Out")
    2. m_fsw.EnableRaisingEvents = True
    3. m_fsw.Filter = "*.txt"


    Für Testzwecke habe ich jetz bei "Created" eine Msgbox hinterlegt. Es funktioniert auch alles,
    aber anscheinend erstellt das Analyse-Programm beim Start bereits eine Temp-Datei, die den Filewatcher
    auslöst. Sobald die Analyse beendet ist, löst der Filewatcher nochmals aus.

    Kann ich den Filewatcher so einstellen, dass nur "richtig" erzeugte Dateien auslösen?

    Dankeeee

    Eierlikörchen schrieb:

    löst der Filewatcher nochmals aus.
    Der FileSystemWatcher hat Flags, worauf er reagieren soll: FileSystemWatcher.NotifyFilter
    die musst Du entsprechend konfigurieren.
    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!
    Ich muss nochmal nerven ... :-/

    Es läuft jetzt alles grds. so wie ich es mir vorstelle. Ich habe jetzt noch eine Textbox und eine Checkbox hinzugefügt.
    Textbox = Mailadresse / Checkbox = Emailbenachrichtigung an / aus

    Ich habe jetzt im Formloader eingefügt:

    Quellcode

    1. If My.Settings.MailAct = True 'Checkbox aktiviert?
    2. Then
    3. m_fsw = New IO.FileSystemWatcher(Application.StartupPath & "\Out")
    4. m_fsw.EnableRaisingEvents = True
    5. m_fsw.Filter = "*.txt"
    6. End If


    Wenn die Checkbox aktiviert ist, dann läuft das auch flüssig. Am Ende der Analyse kommt dann die Msgbox.

    Wenn ich jetzt aber die Checkbox deaktiviere, kommt richtigerweise keine Msgbox >> perfekt!!

    Wenn ich dann nach drei Analysen die Checkbox (Email-Benachrichtigung) wieder aktiviere, dann kommt
    nicht eine Msgbox, sondern alle Msgboxen die "gesammelt" wurden, als die Checkbox nicht aktiviert war.

    Ich habe bei Google nichts gefunden, wie ich den Filewatcher nur einschalten kann, wenn die Checkbox aktiv ist
    und er ab diesem Zeitpunkt auch nur das Verzeichnis überwacht. Anscheinend überwacht er das Verzeichnis die ganze
    Zeit ....

    Wie kann ich das am besten lösen?
    @Eierlikörchen Das klingt jetzt etwas merkwürdig, zur Analyse solltest Du vielleicht das Projekt anhängen.
    obj, bin, .vs-Verzeichnisse löschen, alles zippen und anhängen:
    Erweiterte Antwort - Dateianhänge - Hochladen.
    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!