Forum: PC-Programmierung C# - cmd.exe ReadLine nicht an undefiniertem Ende warten lassen


von Der Unwissende (Gast)


Lesenswert?

Hallo, ich starte von meiner C# Anwendung aus eine Eingabeaufforderung, 
in welche ich über ein WriteLine dann diverse Commandos schreibe.

Nun sind die Ausgaben nicht immer gleich lang, womit sich ReadLine 
aufhängt wenn nichts mehr abzuholen ist bzw. halt auf eine Eingabe in 
der cmd wartet.
Lesen bis Ende funktioniert auch nicht, da ja keins existiert.

Der Versuch ein Timeout zu setzen ist daran gescheitert, dass dies cmd 
nicht unterstützt.

Wie wird so was denn klassicherweise gemacht, das problem gibt es ja 
bestimmt auch noch mit anderen Programmen.

Meine Lösungsideen (finde ich jeweils nicht schön):

1. Am Ende ein Sonderzeichen hinterherschicken z.B. ein å (gesprochen o) 
welches eher nicht in einer Ausgabe zu erwarten ist als bessere Option.

2. Einen zweiten Thread aufmachen, welcher überprüft ob der andere sich 
aufgehangen hat und evtl. einfach ein beenden Flag setzt und eine neue 
Zeile erzeugt.

3. Über einen Kill-Thread den anderen vernichten, sollte er sich nicht 
zurückmelden. Allerdings wird dann die Anfrage sauber aufgelöst?

4. Alle Befehle direkt über C# ausführen, dann aber immer noch nicht 
sicher das es klappt und nicht wieder der gleiche Effekt auftritt.

von Skalpell (Gast)


Lesenswert?

Zitat: "Nun sind die Ausgaben nicht immer gleich lang, womit sich 
ReadLine
aufhängt wenn nichts mehr abzuholen ist bzw. halt auf eine Eingabe in
der cmd wartet."

äääh du meinst Eingang?

Zitat: "Lesen bis Ende funktioniert auch nicht, da ja keins existiert."

Alles hat ein Ende nur die Wurst hat 2!


Ich verstehe irgendwie nicht ganz was du jetzt vor hast, was für Befehle 
sollen das sein, deine eigenen?

Hilft dir vielleicht eine Datei mit der Endung .bat weiter?

Ansonsten kannst du ja das Ende eines Strings wenn es mit 0 terminiert 
ist durch das NULLbyte finden!

Es wäre hilfreich, wenn du zeigst wie du deine Eingabeaufforderung mit 
C# startest!

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Meinst Du tatsächlich eine "Eingabeaufforderung", sprich, Du startest 
"cmd.exe" als neuen Prozess, oder machst Du nur ein Konsolenfenster auf?

von Der Unwissende (Gast)


Lesenswert?

@rufus & Skalpell

Ja, ich starte wirklich eine cmd.exe von meinem Prozess aus. An eine 
.bat hatte ich auch schon gedacht, würde es aber lieber ohne machen, 
stelle ich jetzt mal so ohne Begründung in den Raum. Evtl. wäre es 
einfach besser alle Programme als Prozess von meinem Programm aus zu 
starten und nicht den Umweg über cmd zu gehen. Allerdings wurmt es mich 
auch das nicht sauber umgesetzt zu bekommen.

Hier der aufruf vom Programm
1
System.Diagnostics.Process p = new System.Diagnostics.Process();
2
      p.StartInfo.UseShellExecute = false;
3
      p.StartInfo.FileName = "cmd.exe";
4
      p.StartInfo.RedirectStandardOutput = true;
5
      p.StartInfo.CreateNoWindow = true;
6
      p.StartInfo.RedirectStandardInput = true;
7
      p.Start();

Einlesen wird dann später mit:
Console.WriteLine(p.StandardOutput.ReadLine());
gemacht.

Dann führe ich Befehle aus und will immer abfragen ob die erfolgreich 
waren, wenn nicht, wird irgendwann (in ferner Zukunft) einmal eine 
E-Mail an mich geschickt.
Nun folgende Situation, nicht alle aufgerufenen Programme sind von mir 
...

Write XXX Data Bytes
Verify supertoll
succesfull

oder so, also drei Zeilen
jetzt Fehlermeldung zB

Write XX DataByes
Verify fehlgeschlagen ...

Wenn ich jetzt drei Zeilen auslese bleibt er bei Variante 2 hängen, da 
er noch auf eine Zeile wartet.
Andererseits wenn 4 Zeilen erzeugt würden als Fehlermeldung, würde ich 
mir auch gerne langfristig 4 schicken und nicht nur 3.

Habe auch schon versucht ein Timeout einzustellen, aber das unterstützt 
die cmd.exe nicht. Schön wäre es ja ob ich auch über cmd.exe die 
information bekommen könnte, ob das aufgerufenen Programm fertig ist und 
wieviele Zeilen abzuholen sind.

Auch langfristig:
Wenn der Prozess eine unerwartete Fehlermeldung bekommt, soll immer ein 
zweiter Versuch gestartet werden und wenn das auch nicht klappt mit 
anderen Aufgaben fortgefahren werden. Also auch im Fehlerfall sollte es 
nicht steckenbleiben.

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Der Unwissende schrieb:
> Schön wäre es ja ob ich auch über cmd.exe die
> information bekommen könnte, ob das aufgerufenen Programm fertig ist und
> wieviele Zeilen abzuholen sind.
Ruf die doch anstelle der CMD direkt auf, dafür ist die Prozess Klasse 
doch da, so ist das etwas... äh... ungünstig.
Dann kriegst du nämlich u.A. auch den Returncode zurückgeliefert.

von Sam P. (Gast)


Lesenswert?

Du solltest wirklich kein cmd.exe benutzen, wenn du in Wirklichkeit 
andere Prozesse starten willst. Welchen Sinn macht denn da der 
Zwischenschritt cmd.exe? Starte die gewünschten Befehle doch einfach 
direkt, genau so wie du cmd.exe gestartet hast. Das ist die einzige 
sinnvolle Variante.

Und damit erledigt sich dann auch dein Problem: Es gibt beim Lesen ein 
Dateiende, nämlich wenn sich der Kindprozess beendet hat. Du kannst dann 
ganz entspannt einfach lesen bis EOF und gut.

Für den unwahrscheinlichen Fall, dass du cmd.exe wirklich ehrlich 
brauchst (ich wüsste keinen guten Grund, es sei denn du musst mit 
Benutzereingaben arbeiten, die Features von cmd.exe nutzen, z.B. 
Umlenkung der Ausgabe, Aliases usw.), starte cmd.exe /c "befehl", damit 
beendet sich cmd.exe nach der Abarbeitung von "befehl" und du hast 
wieder ein EOF.

von Skalpell (Gast)


Lesenswert?

Der Unwissende

wenn du eine .bat mit dem inhalt "ping google.com > ret.txt" startest 
findest du das ergebnis in ret.txt vielleicht hilft das ein bissien. 
ansonsten gibt es auch 
http://dotnet-snippets.de/dns/shellexecute-SID1000.aspx
und viele viele weitere möglichkeiten ist die cmd.exe denn eine 
voraussetzung oder kennst du nur keine andere möglichkeit :-)?

von Sebasrian L. (Gast)


Lesenswert?

Hi also das geht eigntlich schon
 eig mal deinen ganzn code und schau dir mal genau die process klasse an 
die bietet viele events

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.