2014-11-03 3 views
0

Я искал везде, но я просто не могу найти правильный ответ.Как писать и читать в процессе без использования useshellexecute = false

Я использую VS2013> C#> Windows Forms-приложений

Ниже вы видите рабочую версию моего процесса. Но у меня есть две небольшие проблемы, которые я не знаю, как исправить.

  1. * .exe - это алгоритм оптимизации, который отображает каждую итерацию, которую он делает, и текущее лучшее решение, которое он нашел. -> но из-за того, что у меня есть «usehellexecute = false», я ничего не вижу в командной оболочке

  2. Пользователь может в любой момент перехватить алгоритм, нажав «Ctrl + C», и алгоритм остановится и вернется в настоящее время лучшим решением -> а потому, что у меня есть «useshellexecute = ложь» Я не могу Imput любые ключевые команды

Как я могу это исправить ?? - Мне нужно увидеть взаимосвязи и нажать «Ctrl + C». - Это не должно быть в командной оболочке, я бы схожу с альтернативным «интерфейсом». - Если я устанавливаю 'useshellexecute = true', как я могу вводить команды и читать все строки.

Обратите внимание:

P.StartInfo.Arguments 

для ввода команды не работает. * .exe приведет к ошибке «invalite input».

код, который работает:

private void btn_Optimize_Start_Click(object sender, EventArgs e) 
    { 
     Process P = new Process(); 

     P.StartInfo.FileName = @Application.StartupPath + @"\Algorithm.exe"; 
     P.StartInfo.UseShellExecute = false; 
     P.StartInfo.RedirectStandardInput = true; 
     P.StartInfo.RedirectStandardOutput = true; 
     P.StartInfo.RedirectStandardError = true; 

     P.Start(); 
     //sets timelimit 30 min 
     P.StandardInput.WriteLine("set lim tim 1800"); 
     //reads the modell for which an optimal solution has to be found 
     P.StandardInput.WriteLine("read modell.zpl"); 
     //command that starts the optimization algorithm 
     P.StandardInput.WriteLine("optimize");   //this part can take hours 
     //command that displays the solution 
     P.StandardInput.WriteLine("display solution"); 
     //ends the *.exe 
     P.StandardInput.WriteLine("quit"); 

     //saves all information in a log-file with which I can work 
     string[] log = P.StandardOutput.ReadToEnd().Split(new string[] { Environment.NewLine }, StringSplitOptions.None); 

     //opens a function, that formats the solution 
     this.result_create(log); 
    } 

редактировать 11.11.2014/Каскадный процесс/выход в RichTextBox:

private void btn_Optimize_Start_Click(object sender, EventArgs e) 
    { 
     Process P = new Process(); 

     P.StartInfo.FileName = @Application.StartupPath + @"\Algorithm.exe"; 
     P.StartInfo.UseShellExecute = false; 
     P.StartInfo.RedirectStandardInput = true; 
     P.StartInfo.RedirectStandardOutput = true; 
     P.StartInfo.RedirectStandardError = true; 
     //*** NEW *** Event Handler for the asynchron Output-Process 
     P.OutputDataReceived += new DataReceivedEventHandler(this.Asyn_Process); 

     P.Start(); 

     //*** NEW *** Starts asynchron Output-Process 
     P.BeginOutputReadLine(); 

     //sets timelimit 30 min 
     P.StandardInput.WriteLine("set lim tim 1800"); 
     //reads the modell for which an optimal solution has to be found 
     P.StandardInput.WriteLine("read modell.zpl"); 
     //command that starts the optimization algorithm 
     P.StandardInput.WriteLine("optimize");   //this part can take hours 
     //command that displays the solution 
     P.StandardInput.WriteLine("display solution"); 
     //ends the *.exe 
     P.StandardInput.WriteLine("quit"); 

     //*** DELETED *** 
     //saves all information in a log-file with which I can work 
     //string[] log = P.StandardOutput.ReadToEnd().Split(new string[] { Environment.NewLine }, StringSplitOptions.None); 

     //opens a function, that formats the solution 
     //this.result_create(log); 
    } 

    //*** NEW *** The asynchronous Process 
    private void Asyn_Process(object sender, DataReceivedEventArgs e) 
    { 
     if (this.rTB_Log.InvokeRequired && e.Data != null) 
     { 
      //Anonym Invoke Function 
      this.rTB_Log.Invoke(new MethodInvoker(delegate() 
      { 
       //Writes Output continuously in the RichTextBox 
       this.rTB_Log.Text += e.Data + Environment.NewLine; 
       //Scroll to End of RichTextBox continuously 
       this.rTB_Log.SelectionStart = this.rTB_Log.Text.Length; 
       this.rTB_Log.ScrollToCaret();       
      })); 
     } 
     //When the process has finished (e.Data == null) 
     else 
     { 
      //Anonym Invoke Function 
      this.rTB_Log.Invoke(new MethodInvoker(delegate() 
      { 
       //Saves the RichTextBox-Content in a Text-File 
       this.rTB_Log.SaveFile(Algorithm.log", RichTextBoxStreamType.PlainText); 
      })); 
     } 
    } 
+0

Избавьтесь от 'InvokeRequired'. Это не ошибка вызова 'Invoke', когда вам это не нужно, и было бы ошибкой пропустить эту логику. –

ответ

0

Во-первых, вы не получаете никакой пользы от UseShellExecute = true. Это только побочные эффекты - ShellExecute несовместим с перенаправлением, и поэтому вы видите, что происходит без перенаправления.

Основная проблема заключается в том, что вам нужно вывести программу из двух мест. В Unix вы должны использовать tee для отправки вывода как на консоль, так и на файл (или псевдофайл) по вашему выбору, ваше приложение будет читать этот файл, чтобы получить результаты.

В Windows нет готовых инструментов, которые делают это, но все необходимые детали есть. Подход вы хотите:

  1. Использование перенаправления, не ShellExecute
  2. Прочитайте вывод приложения непрерывно, а не с ReadToEnd()
  3. Все, что вы читали из приложения ребенка, а также показать пользователю. Отправка его в собственное консольное окно прекрасна, но в равной степени допустимо выгружать его в текстовое поле или анализировать его и делать сюжет.
  4. Когда пользователь хочет прервать поиск, он будет использовать ваш пользовательский интерфейс для этого, потому что дочерний процесс больше не читает его ввод с консоли.И вам придется передать это дочернему процессу, как если бы нажали CTRL + C. Для этого есть функция Win32, GenerateConsoleCtrlEvent. Я не думаю, что есть какая-либо замена .NET, поэтому вам, вероятно, придется использовать p/invoke.
  5. Хуже, как указано в this answer, GenerateConsoleCtrlEvent действует на всю группу процессов, а Process.Start не использует флаг, который создает новую группу, поэтому вам может потребоваться также p/invoke CreateProcess. Это означает, что вам также нужно использовать p/invoke для настройки перенаправления потока, что в основном означает создание каналов и их закрепление в структуре STARTUPINFO, переданной в CreateProcess. Это большая работа. Может быть, вам повезет поделиться группой процессов, и больше ничего в группе не ответит плохо. В документах также говорится: «Только те процессы в группе, которые используют ту же консоль, что и вызывающий процесс, получают сигнал. Другими словами, если процесс в группе создает новую консоль, этот процесс не получает сигнал и не выполняет его потомки «. Поэтому вам также нужно иметь консоль в своем приложении, либо использовать консольную подсистему, либо использовать AllocConsole.
+0

Спасибо за информацию - я боялся столько же. Я редактировал свой код, чтобы читать непрерывно и асинхронно. - Я еще не пробовал GenerateConsoleCtrlEvent, и поскольку это не приоритет, он должен ждать, пока у меня не будет времени. – Beckz

Смежные вопросы