tags:

views:

1999

answers:

2

I want to capture output of a Perl program and display output data (string on screen) in a text box on C# Windows Form.

Here is my main C# code:

public partial class frmMain : Form
{
    private Process myProcess = null;
    public frmMain()
    {
        InitializeComponent();            
    }

    public delegate void UpdateUIDelegate(string data);
    private void btnRun_Click(object sender, EventArgs e)
    {
        myProcess = new Process();
        ProcessStartInfo myProcessStartInfo = new ProcessStartInfo("perl.exe");
        myProcessStartInfo.Arguments = "test.pl";
        myProcessStartInfo.UseShellExecute = false;
        myProcessStartInfo.RedirectStandardOutput = true;
        myProcessStartInfo.WindowStyle = ProcessWindowStyle.Hidden;
        myProcessStartInfo.CreateNoWindow = true;
        myProcess.StartInfo = myProcessStartInfo;
        myProcess.OutputDataReceived += new DataReceivedEventHandler(myProcess_OutputDataReceived);
        myProcess.Start();
        myProcess.BeginOutputReadLine(); 
    }

    void myProcess_OutputDataReceived(object sender, DataReceivedEventArgs e)
    {
        if (txtOutput.InvokeRequired)
        {
            UpdateUIDelegate updateDelegate = new UpdateUIDelegate(UpdateUI);                
            this.Invoke(updateDelegate, e.Data);
        }            
    }

    void UpdateUI(string data)
    {
        txtOutput.Text += data + "\r\n";
    }
}

and code for test.pl:

my @a = qw{1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19};
my @b = qw{a b c d e f g h i j  k  l  m  n  o  p  q  r  s };
print 'start' . "\n";
while ( my ( $item1, $item2) = ( splice (@a, 0, 1), splice (@b, 0, 1) ) ) {
    print 'Item 1: ' . $item1 . "\n";
    print 'Item 2: ' . $item2 . "\n";
    warn 'Finish one item' . "\n";
    sleep(1);
}

I have a problem is that the output data is only displayed on text box until the Perl has finished.

It's more interesting when I found that, If I do the same with a console application (C#) everything seems okay.

Here's the code for console application:

class Program
{
    static void Main(string[] args)
    {
        Process myProcess = new Process();
        ProcessStartInfo myProcessStartInfo = new ProcessStartInfo("perl.exe");
        myProcessStartInfo.Arguments = "test.pl";
        myProcessStartInfo.UseShellExecute = false;
        myProcessStartInfo.RedirectStandardOutput = true;
        myProcess.StartInfo = myProcessStartInfo;

        myProcess.OutputDataReceived += new DataReceivedEventHandler(myProcess_OutputDataReceived);                                    
        myProcess.Start();            
        myProcess.BeginOutputReadLine();            
        Console.Read();
    }

    static void myProcess_OutputDataReceived(object sender, DataReceivedEventArgs e)
    {
        Console.WriteLine(e.Data);
    }
}

I'm trying to figure out what happens with my form application but still not find any clue. One more thing is that I can not get warn message with windows form application.

+2  A: 

First you have to update the event handler

    void myProcess_OutputDataReceived(object sender, DataReceivedEventArgs e)    
    {        
         if (txtOutput.InvokeRequired)        
         {            
               UpdateUIDelegate updateDelegate = new UpdateUIDelegate 

                 (UpdateUI);this.Invoke(updateDelegate, e.Data);        
          }
          else UpdateUI(e.Data);

     }

and add this line in your btnRun_Click

proc.WaitForExit();
Ahmed Said
First, calling proc.WaitFroExit(); make the main thread (UI Thread) wait until the Perl program has finished. I don't want that. I want the program is more responsive. In fact, the perl program will run in several hours.
Minh Le
+2  A: 

You're going to need to use multiple threads so it doesn't interupt your UI. I have a fairly large utility class that launches processes on its own thread and pipes to delegated events.

Sorry, I'd give an example but I'm actually in a huge rush. But one thing else you will want to watch out for with using Perl scripts is that they do not auto flush the output nicely. You need to put:

local $| = 1;

At the top of your script that you're running so it auto flushes.

Balk
Thank you, It works like magic :)
Minh Le