从重定向的输入/输出/错误与(Python)进程交互时未触发DataReceivedEvent

时间:2016-10-21 13:03:27

标签: c# python winforms stdout stdin

我正在尝试使用标准输入和扩展来控制C#中的python会话。输出

启动Python进程后,我希望继续向它发送命令并将输出接收到我的WinForms文本框。

尝试了很多SO答案和MSDN之后,有关为什么DataReceivedEvent处理程序未被调用的任何建议?完整代码如下:

请注意,要从Python生成Newline,请在命令文本import os;print os.linesep

中输入
using System;
using System.Diagnostics;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        private static Process InterProc;
        public Form1()
        {
            InitializeComponent();
            InterProc = new Process();
            InitializeInterpreter();
        }

        private void InitializeInterpreter()
        {
            InterProc.StartInfo.UseShellExecute = false;
            InterProc.StartInfo.FileName = @"C:\Python27\python.exe";
            InterProc.StartInfo.RedirectStandardInput = true;
            InterProc.StartInfo.RedirectStandardOutput = true;
            InterProc.StartInfo.RedirectStandardError = true;
            InterProc.StartInfo.CreateNoWindow = true;
            InterProc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
            InterProc.OutputDataReceived += new DataReceivedEventHandler(InterProcOutputHandler);

            bool started = InterProc.Start();

            InterProc.BeginOutputReadLine();
        }

        private void AppendTextInBox(TextBox box, string text)
        {
            if (this.InvokeRequired)
            {
                this.Invoke((Action<TextBox, string>)AppendTextInBox, OutputTextBox, text);
            }
            else
            {
                box.Text += text;
            }
        }

        private void InterProcOutputHandler(object sendingProcess, DataReceivedEventArgs outLine)
        {
            AppendTextInBox(OutputTextBox, outLine.Data + Environment.NewLine);
        }

        private void Enterbutton_Click(object sender, EventArgs e)
        {
            InterProc.StandardInput.WriteLine(CommandTextBox.Text);
        }
    }
}

2 个答案:

答案 0 :(得分:1)

这可能对上面的解决方案不起作用的其他人有所帮助。 我遇到了完全相同的问题,并且一直在苦苦挣扎,最终找到了这个问题和答案。

对我来说,通过StdError的{​​{1}}被触发以进行错误输出,而只是通过ErrorDataReceived的{​​{1}}未被触发。

我在Linux(Raspberry Pi)上运行dotnet core,但是在Windows上运行它也遇到了同样的问题。

我的代码与vijiboy的答案基本相同,因此我在Python中添加了Stdout选项,但没什么区别!但这启发了我仔细研究发现它的Python选项:

-u:强制stdout和stderr流不被缓冲; 此选项对stdin无效;也PYTHONUNBUFFERED = x

因此在调用Python时添加-u(删除-i)解决了该问题,最后触发了OutputDataReceived

答案 1 :(得分:0)

这个答案适用于那些在这里登陆的人,他们希望在SO上有许多答案。

最终与python会话交互的代码如下:
注1:使用&#39; -i&#39;调用Python论点。 (请参阅下面的流程参数-i
注2:尝试从std错误冻结(Process.StandardError.ReadToEnd())进行同步读取。因此std输出和错误流都需要通过处理程序回调(请参阅下面的InterProcOutputHandler

using System;
using System.Diagnostics;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        private static Process InterProc;
        public Form1()
        {
            InitializeComponent();
            InterProc = new Process();
            InitializeInterpreter();
        }

        private void InitializeInterpreter()
        {
            InterProc.StartInfo.FileName = @"C:\Python27\python.exe";
            InterProc.StartInfo.Arguments = @"-i"; // drops python into interactive mode after executing script if passed any
            InterProc.StartInfo.UseShellExecute = false;
            InterProc.StartInfo.RedirectStandardInput = true;
            InterProc.StartInfo.RedirectStandardOutput = true;
            InterProc.StartInfo.RedirectStandardError = true;
            InterProc.StartInfo.CreateNoWindow = true;
            InterProc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
            InterProc.OutputDataReceived += new DataReceivedEventHandler(InterProcOutputHandler);
            InterProc.ErrorDataReceived += new DataReceivedEventHandler(InterProcOutputHandler);

            bool started = InterProc.Start();

            InterProc.BeginOutputReadLine();
            InterProc.BeginErrorReadLine();
        }

        private void AppendTextInBox(TextBox box, string text)
        {
            if (InvokeRequired)
            {
                Invoke((Action<TextBox, string>)AppendTextInBox, OutputTextBox, text);
            }
            else
            {
                box.Text += text;
            }
        }

        private void InterProcOutputHandler(object sendingProcess, DataReceivedEventArgs outLine)
        {
            AppendTextInBox(OutputTextBox, outLine.Data + Environment.NewLine);
        }

        private void Enterbutton_Click(object sender, EventArgs e)
        {
            InterProc.StandardInput.WriteLine(CommandTextBox.Text);
        }
    }
}