Link to home
Start Free TrialLog in
Avatar of nikez2k4
nikez2k4Flag for United Kingdom of Great Britain and Northern Ireland

asked on

Execute Python Script in C# (VS2005)

Hi,

I've got a python script (which currently runs in a batch-file):

c:\Python25\python.exe c:\main.py

I'd like to run this via a C# application I'm developing.  I've wrestled with this for a while now (calling python.exe directly, or just using the batch file) and because the python script runs indefinitely (it monitors port activity (and other things)) I've been unable to start the process and redirect the contents of (what would usually be) the console output to a textbox like I would with say, a directory listing or cmd shell operation.

The script is designed to only be run once at any one time and if you run the script twice it returns a friendly error message.  

When I try this with my app, I can see the process starting Python.exe in task manager but the UI doesnt load until I kill python.exe.  If I try and run it twice, the UI loads and displays the error message correctly:

---
    Process P = new Process();

    P.StartInfo.FileName = @"c:\test.bat";
    P.StartInfo.UseShellExecute = false;
    P.StartInfo.RedirectStandardOutput = true;
    P.StartInfo.CreateNoWindow = true;
    P.Start();  
    string Output = P.StandardOutput.ReadToEnd();
    textBox1.Text = Output.ToString();
---

I've created/killed processes before but this one is killing *me*!  Can anyone show me the best way to start this script and consistently view the ouput please?

Thanks!


ASKER CERTIFIED SOLUTION
Avatar of Bob Learned
Bob Learned
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of nikez2k4

ASKER

Thanks for this, I'm gonna check it out and report back.  Handy Event Handler, if it works!
Definitely a handy Event Handler!  Thanks.
Thought I'd post my solution in case anyone else has a similar problem.

As well as using OnOutputDataReceived I also had to nab the SetText code (SetTextCallback d = new SetTextCallback(SetText)) from http://www.codeproject.com/KB/system/rs232ThreadSafe.aspx so ended up with:

-
        delegate void SetTextCallback(string text);
        private Process P;
       
        private void StartAPS()
      {  

            try

            {   int score =0;
                string python = @"C:\\Python25\\python.exe";
                string pyscript = "c:\\aps\\main.py";
                P = new Process();
                P.OutputDataReceived += new DataReceivedEventHandler(OnOutputDataReceived);
                P.ErrorDataReceived += new DataReceivedEventHandler(OnOutputDataReceived);
                P.StartInfo.UseShellExecute = false;
                P.StartInfo.RedirectStandardOutput = true;
                P.StartInfo.RedirectStandardError = true;
                P.StartInfo.CreateNoWindow = true;
                P.StartInfo.FileName = @python.ToString();
                P.StartInfo.Arguments = "-u "+ pyscript.ToString();
                P.Start();
                P.BeginOutputReadLine();
                P.BeginErrorReadLine();
            }

                else { MessageBox.Show("ERR!"); return; }

            }

            catch (Exception aps)
            {
                MessageBox.Show(aps.ToString());
            }

        }




        private void OnOutputDataReceived(object sender, DataReceivedEventArgs e)  
        {
            try
            {

                SetText(e.Data.ToString());
            }

            catch (Exception OODR)
            {
                MessageBox.Show(OODR.ToString());
            }


       }
 
      private void SetText(string text)
      {
            if (this.textBox1.InvokeRequired)  
            {  
                SetTextCallback d = new SetTextCallback(SetText);  
                this.Invoke(d, new object[] { text });  
            }  
            else this.textBox1.Text += text;  
      }

---
Also note I couldn't use the batch file (which simply called python and the script) - dont know why, but this worked perfectly fine.
The -U used in the process argument for the python script is (quote):
"-u     : unbuffered binary stdout and stderr (also PYTHONUNBUFFERED=x)

That's the simplified versions without all the exception catches, friendly resource names,  and so on.  Hope that helps someone.
Thanks for this, couldn't have finished it without your help!