如何在没有'useshellexecute = false'的过程中编写和读取

时间:2014-11-03 16:23:16

标签: c# input process output invoke

我到处寻找,但我找不到合适的答案。

我使用VS2013> C#> Windows Forms-Application

下面你会看到我的流程的工作版本。 但我有两个小问题,我不知道如何修复。

  1. * .exe是一种优化算法,它显示它所执行的每次迭代以及它找到的当前最佳解决方案。 - >但是因为我已经使用了'hellexecute = false'我在命令shell中看不到任何内容

  2. 用户可以通过按“Ctrl + C”键随时中断算法。并且算法将停止并返回当前最佳解决方案 - >但是因为我已经使用了'hellexecute = false'我不能插入任何键命令

  3. 我该如何修复? - 我需要查看内容,并能够按下Ctrl + C'。 - 它不必在命令shell中,我可以使用一个替代"接口"。 - 如果我设置' useshellexecute = true'如何输入命令并读取所有行。

    请注意:

    P.StartInfo.Arguments
    

    输入命令不起作用。 * .exe将提供" invalite输入"错误。

    有效的代码:

    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);
                }));
            }
        }
    

1 个答案:

答案 0 :(得分:0)

首先,您没有从UseShellExecute = true获得任何好处。这只是副作用 - ShellExecute与重定向不兼容,因此您可以看到没有重定向的情况。

您的核心问题是您需要从程序输出两个位置。在Unix上,您使用tee将输出发送到控制台和您选择的文件(或伪文件),您的应用程序将读取该文件以获得结果。

Windows没有现成的工具可以做到这一点,但所有必要的部分都在那里。你想要的方法是:

  1. 使用重定向,而不是ShellExecute
  2. 连续阅读应用程序输出,而不是ReadToEnd()
  3. 您从子应用程序中读取的所有内容也会向用户显示。将它发送到您自己的控制台窗口是可以的,但将它转储到文本框中,或解析它并制作图表同样有效。
  4. 当用户想要中断搜索时,他们会使用您的UI来执行此操作,因为子进程不再从控制台读取其输入。并且您必须将其传递给子进程,就像按下CTRL + C一样。有一个Win32函数,GenerateConsoleCtrlEvent。我不认为有任何.NET替换,所以你可能不得不使用p / invoke。
  5. 更糟糕的是,正如this answer中所述,GenerateConsoleCtrlEvent对整个流程组起作用,而Process.Start并未使用创建新群组的旗帜,因此您可以还需要p / invoke CreateProcess。这意味着您还必须使用p / invoke来设置流重定向,这基本上意味着创建管道并将其粘贴到传递给STARTUPINFO的{​​{1}}结构中。这需要做很多工作。也许你很幸运地分享了这个过程组,并且该小组中的其他任何事情都没有得到很好的响应。文档还说"只有组中与调用进程共享同一控制台的那些进程才会收到信号。换句话说,如果组中的进程创建了一个新控制台,那么该进程就不会收到信号,也不会收到它的后代。"因此,您也需要在应用程序中安装控制台,使用控制台子系统或使用CreateProcess