Laden...

Process Funktion mit blockierendem StandartInput

Letzter Beitrag vor 13 Tagen 3 Posts 166 Views
Process Funktion mit blockierendem StandartInput

Hallo,

ich habe ein kleines Problem das ich nicht verstehe. Ich habe ein Process das ein Kommandozeilentool aufruft. Es funktioniert soweit ganz gut, allerdings kann ich die Daten aus dem Kommandozeilentool nur lesen wenn ich den StandartInput schließe mit proc.StandardInput.Close();. Das Problem ist, das ich dann natürlich keine neuen Befehle an das Tool schicken kann. Ich möchte aber auf die Ausgaben reagieren und dann etwas dahin schicken. Ich habe das ein paar mal ausprobiert, sobald der StandartInput geschlossen wird, kommen die Daten.

Habe ich da einen Denkfehler oder kann mir einer erklären warum der StandartInput den Output blockiert?

MFG

private void Test4()
       {
           var proc = new Process
           {
               StartInfo = new ProcessStartInfo
               {
                   FileName = "C:\\Program Files (x86)\\Elprotronic\\MSP430\\FET-Pro430\\CMD-Line\\FP430-commandline.exe",
                   UseShellExecute = false,
                   RedirectStandardOutput = true,
                   RedirectStandardInput = true,
                   CreateNoWindow = false
               }
           };
           proc.Start();
           StringBuilder sb = new StringBuilder();
           var outStream = proc.StandardOutput;
           var inStream = proc.StandardInput;
           inStream.WriteLine("help()");
           List<string> lines = new List<string>();
           Task.Run(() =>
           {
               while (true)
               {
                   Console.WriteLine(outStream.ReadLine());
                   lines.Add(outStream.ReadLine());
               }
           });
           var timer = new Stopwatch();
           timer.Start();
           bool ProgResult = false;
           inStream.WriteLine("F_Initialization()");
           proc.StandardInput.Close();
           while (!ProgResult)
           {
               Thread.Sleep(100);
               //Print Results
               tb_programmingInfo.Text = String.Join(" \r\n - ", lines.ToArray());
               tb_programmingInfo.Update();
               //Abort Function
               TimeSpan timeTaken = timer.Elapsed;
               if (timeTaken.TotalSeconds > 10 || lines.Count() > 100)
                   ProgResult = true;
           }
           timer.Stop();
           //proc.StandardInput.Flush();
           //proc.StandardInput.Close();
           proc.WaitForExit(2000);
           if (!proc.HasExited)
               proc.Kill();
       }

Das is im Endeffekt ganz schöner Spaghetti-Code.

Das grundlegende Problem ist, dass Du alles im UI-Thread ausführst. Du blockierst damit die gesamte UI-Interaktion und alles, was dazugehört. Besonders das while(!ProgResult) ist dafür schuld.
[FAQ] Warum blockiert mein GUI?

Der ganze Code hat aber ohnehin in der UI sowieso nichts zu suchen ([Artikel] Drei-Schichten-Architektur). Du musst also alles auslagern in einen eigenen Task; und nicht nur das ReadLine. Im Endeffekt sogar 2 Tasks.

Mach Dir also eine saubere Klasse zur Kommunikation, und arbeite zB mit Events für UI-Infos statt das alles so zu verwursteln.

Und als weiterer Hinweis bzgl. "Events für UI-Infos" s. [FAQ] Controls von Thread aktualisieren lassen (Control.Invoke/Dispatcher.Invoke).

Alternativ den kompletten Code auf asynchron (async/ await) umstellen.

PS:
Außerdem solltest du keine absoluten Pfade auf Windowsverzeichnisse direkt im Code benutzen, sondern dafür dann Environment.GetFolderPath benutzen.