Executing an external application....and getting its output (1 Viewer)

egonspengleruk

Retired Team Member
  • Premium Supporter
  • June 30, 2005
    250
    0
    How do I call an external application from within a plugin? I need to call a specific exe with specific parameters and be able to monitor its output and show it on the screen. I also need to know when its completed so I can launch anyone exe.
    I know the code it has to be in MyPrograms somewhere.....but I cant for the life of my find it :p

    Egon
     

    mPod

    Portal Pro
    January 26, 2005
    2,084
    3
    Berlin
    Home Country
    Germany Germany
    System.Diagnostics.Process contains all you need...

    Code:
    public static Process Start (
    	string fileName,
    	string arguments
    )
    and
    Code:
    public bool HasExited { get; }
    or
    Code:
    public bool EnableRaisingEvents { get; set; }
    and
    Code:
    public StreamReader StandardOutput { get; }
    for example.... See MSDN help for more details. :wink:
     

    egonspengleruk

    Retired Team Member
  • Premium Supporter
  • June 30, 2005
    250
    0
    mPod said:
    System.Diagnostics.Process contains all you need...

    Code:
    public static Process Start (
    	string fileName,
    	string arguments
    )
    and
    Code:
    public bool HasExited { get; }
    or
    Code:
    public bool EnableRaisingEvents { get; set; }
    and
    Code:
    public StreamReader StandardOutput { get; }
    for example.... See MSDN help for more details. :wink:

    Ah....I was missing the "System.Diagnostics." part.
    Ive to all my exe's running but I need to be able to get their output to show to the user. All the bits on MSDN seem to only get the final output in one go.....so I googled a bit more and found http://www.codeproject.com/csharp/LaunchProcess.asp Ive dropped all the code into my Plugin, but the line
    Code:
    processCaller = new ProcessCaller(this);
    gives me an error of
    Code:
    Error	2	Argument '1': cannot convert from 'MediaPortal.GUI.GUIBurner.GUIBurner' to 'System.ComponentModel.ISynchronizeInvoke'	C:\Documents and Settings\Mat Key\Desktop\My Burner\Sources\GUIBurner.cs	1293	57	My Burner
    So what is a MP Plugin's version of "this" ?

    Egon
     

    mPod

    Portal Pro
    January 26, 2005
    2,084
    3
    Berlin
    Home Country
    Germany Germany
    Try to make GUIBurner also an ISynchronizeInvoke (class declaration). If you wanna hand it over as a delegate, it has to implement the methods used for callback. See MSDN documentation and a good C# book for details. Or Google... :-P

    Didn't look deeper into it, but that's the impression I get at first sight from your post. So I could be wrong. ;-)
     

    samuel337

    Portal Pro
    August 25, 2004
    772
    0
    Melbourne, Australia
    That article doesn't take advantage of the new .NET 2.0 features in System.Diagnostics.Process. I've just completed a project involving this sort of stuff, so here's some code:

    Code:
    System.Diagnostics.Process newProcess;
    
    private void StartSomething()
    {
                //build processstartinfo object
                System.Diagnostics.ProcessStartInfo psi = new System.Diagnostics.ProcessStartInfo();
                psi.RedirectStandardOutput = true;
                psi.UseShellExecute = false;
                psi.EnableRaisingEvents = true;
    
                psi.FileName = <replace with filename here>;
    
                newProcess = new System.Diagnostics.Process();
                newProcess.StartInfo = psi;
    
                newProcess.Start();
    
                newProcess.OutputDataReceived += new System.Diagnostics.DataReceivedEventHandler(newProcessOutputHandler);
                newProcess.BeginOutputReadLine();
    }
    
            private void newProcessOutputHandler(object sender, System.Diagnostics.DataReceivedEventArgs e)
            {
                //do stuff here. Use e.Data to get the outputted line
            }
    
    //to determine if something has exited, use newProcess.HasExited, or listen in on the Exited event of the newProcess object

    Now I assume that you want to do something useful with the outputted lines, something like display them in a text box. Note that the eventhandler runs in a different thread to the UI thread, hence in order to do something to the UI, you need to use delegates/callbacks. Here's some more code (from MSDN) to do that:

    Code:
            delegate void WriteConsoleOutputCallback(string output);
    
            private void WriteToConsoleOutputBox(string text)
            {
                // InvokeRequired required compares the thread ID of the
                // calling thread to the thread ID of the creating thread.
                // If these threads are different, it returns true.
                if (this.txtConsoleOutput.InvokeRequired)
                {
                    WriteConsoleOutputCallback callBack = new WriteConsoleOutputCallback(WriteToConsoleOutputBox);
                    this.Invoke(callBack, new object[] { text });
                }
                else
                {
                    txtConsoleOutput.Text += Environment.NewLine + text;
                    txtConsoleOutput.SelectionStart = txtConsoleOutput.Text.Length;
                    txtConsoleOutput.ScrollToCaret();
                }
            }

    This code assumes you have a textbox called txtConsoleOutput and it has the multiline property enabled.

    To use the above code, just change the event handler in the initial code to:
    Code:
            private void newProcessOutputHandler(object sender, System.Diagnostics.DataReceivedEventArgs e)
            {
                WriteToConsoleOutputBox(e.Data);
            }

    HTH

    Sam
     

    egonspengleruk

    Retired Team Member
  • Premium Supporter
  • June 30, 2005
    250
    0
    Hey Sam,

    You got a bug in your sampe code :)
    Your psi.EnableRaisingEvents should be newProcess.EnableRaisingEvents

    Egon
     

    samuel337

    Portal Pro
    August 25, 2004
    772
    0
    Melbourne, Australia
    egonspengleruk said:
    Hey Sam,

    You got a bug in your sampe code :)
    Your psi.EnableRaisingEvents should be newProcess.EnableRaisingEvents

    Egon

    Whoops - sorry about that, I must have missed that bit when I was shortening the code to delete the irrelevant bits.

    Sam
     

    egonspengleruk

    Retired Team Member
  • Premium Supporter
  • June 30, 2005
    250
    0
    samuel337 said:
    egonspengleruk said:
    Hey Sam,

    You got a bug in your sampe code :)
    Your psi.EnableRaisingEvents should be newProcess.EnableRaisingEvents

    Egon

    Whoops - sorry about that, I must have missed that bit when I was shortening the code to delete the irrelevant bits.

    Sam

    Hey Sam,

    Im new to threads and how they operate between each other and as such I cant seem to work out how to get the above to work in MP. Any chance you can tell me how to get your code to work with a MP label? Mainly the .invoke required bit of it. I have a feeling im not the only one who would find this useful. Think it would be useful to have this as part of the plugin tutorial :)

    Egon
     

    samuel337

    Portal Pro
    August 25, 2004
    772
    0
    Melbourne, Australia
    I'm a bit new to threading too; I know the basics, but not some of the harder stuff. I did this for a Windows Form solution, so it was easier there.

    The answer to your problem is that you need your class to implement the ISynchronizeInvoke interface, so then there is a mechanism for the process thread to communicate with the UI thread - all UI related calls should be done on the UI thread (funny things usually happen otherwise).

    Alternatively, you could try using the BackgroundWorker object, which is designed to alleviate this problem.

    I'll see if I can get some time this weekend to dabble with this and post some code.

    Sam
     

    Users who are viewing this thread

    Top Bottom