Executing an external application....and getting its output (2 Viewers)

egonspengleruk

Retired Team Member
  • Premium Supporter
  • June 30, 2005
    250
    0
    samuel337 said:
    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

    Thanks. I have my code executing the commands I want....just need to find some way to showing the user the progress....as currently it takes a long long long while !

    Egon
     

    samuel337

    Portal Pro
    August 25, 2004
    772
    0
    Melbourne, Australia
    Ok, I've knocked up some code. Its not exactly thread-safe due to some missing implementations in the MP code (compared with the winforms code), but it works.

    Note: What I've done can also be accomplished using the backgroundworker object in .NET 2.0. See the Alarm.cs file in MP's source code for more information. However, that method only allows you to report numerical progress for complete thread-safety.

    My code approaches it in a slightly different sort of way, and as I said before, it isn't technically thread-safe (at least I don't think so anyway).

    You can download the sample code at:
    ftp://lai-family.homeip.net/public-web/MultiThreadDemoPlugin.zip

    Copy the dll file in MultiThreadDemoPlugin\bin\debug to your MediaPortal\plugins\windows folder, and the xml file in the same folder to MediaPortal\skin\BlueTwo (or which other skin you're using, though I've only tested it with BlueTwo).

    Now go into MP Configuration and make sure the plugin is enabled, and check that it is on the Menu in the Home plugin setup.

    Now load MP, find the Multi Thread Demo plugin and click!

    A new screen should open almost immediately, and the list should slowly populate (I introduced a delay to show the effect of multi-threading). When its done, it will display a message. IT will display all the files in your C:\windows folder (if you've installed windows elsewhere, this will not work).

    The code's pretty self-explanatory, but feel free to ask questions and make improvements.

    EDIT: whoops, seems like threading is way harder than I thought. I've hit a dead end - the code in this example provides no way to kill the new thread when the window is closed.

    HTH

    Sam
     

    samuel337

    Portal Pro
    August 25, 2004
    772
    0
    Melbourne, Australia
    egonspengleruk said:
    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

    During the coding I realised that you can communicate with MP's GUI controls using threads other than the UI thread, so with the above WriteToConsoleOutputBox method, just write directly to the control and it should work (remove all the code that's in that method now).

    Sam
     

    egonspengleruk

    Retired Team Member
  • Premium Supporter
  • June 30, 2005
    250
    0
    samuel337 said:
    egonspengleruk said:
    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

    During the coding I realised that you can communicate with MP's GUI controls using threads other than the UI thread, so with the above WriteToConsoleOutputBox method, just write directly to the control and it should work (remove all the code that's in that method now).

    Sam

    Hey Sam,

    You are a STAR :)
    Only just seen your reply (for some reason im not getting emails about posts)....and am adding it to the MyBurner plugin now. Many many thanks !!

    Egon
     

    egonspengleruk

    Retired Team Member
  • Premium Supporter
  • June 30, 2005
    250
    0
    I think I have sorted out how to capture the output of an executed file....but how do I run several apps one after each other?

    E.g. I want to run Command1.exe and capture its output, when its finished successfully then run Command2.ex and captures its output............etc

    Egon
     

    egonspengleruk

    Retired Team Member
  • Premium Supporter
  • June 30, 2005
    250
    0
    samuel337 said:
    Listen in on the exit event handler and act accordingly.

    I've forgotten how you've gone about doing what you're doing, can you either post a link to the code or the code here?

    Sam


    Ok, have chopped out a lot....but you should get the idea. I need to call several EXE's in turn from a worker thread...but need to get each ones output.

    Code:
                                  strTemp = (string)FileNamesToBurn[i];
                                  
                                  // If its an AVI then we need to convert to MPEG
                                  if (strTemp.EndsWith("avi") == true)
                                  {
                                      // Convert the AVI to MPG
                                      strTemp = strTemp.Substring(0, (strTemp.Length - 3));
                                      strTemp = strTemp + "mpg";
    
                                      ConvertProcess.StartInfo.FileName = BurnerFilesPath + "ffmpeg.exe";
                                      ConvertProcess.StartInfo.Arguments = "-y -i \"" + FilePathsToBurn[i] + "\" -target pal-dvd \"" + strTempFolder + "\\" + strTemp + "\"";
                                      ConvertProcess.Start();
    
                                      ConvertProcess.OutputDataReceived += new System.Diagnostics.DataReceivedEventHandler(processOutputHandler);
                                      ConvertProcess.BeginOutputReadLine();
                                      
                                      //while (ConvertProcess.HasExited == false)
                                        //  ConvertProcess.BeginOutputReadLine(); 
    
                                      //ConvertProcess.WaitForExit();
    
                                      FileNamesToBurn[i] = strTemp;
                                      FilePathsToBurn[i] = strTempFolder + "\\" + strTemp;
                                  }
    
    
                                  if (strTemp.EndsWith("dvr-ms") == true)
                                  {
                                  // Then we need to convert the file to MPG
                                  //ConvertDvrMs()          // To Do
                                  }
    
                                 // if (strTemp.EndsWith("mpg") == true)
                                  else
                                  {
                                      // Split the MPG into sepearate audio and video parts
                                      ConvertProcess.StartInfo.FileName = BurnerFilesPath + "mpgtx.exe";
                                      ConvertProcess.StartInfo.Arguments = "-f -d \"" + FilePathsToBurn[i] + "\" -b \"" + strTempFolder + "\\" + FileNamesToBurn[i] + "\" ";
                                      ConvertProcess.Start();
                                      ConvertProcess.WaitForExit();
    
                                      // Merge them back together again but with "DVD" required bits
                                      ConvertProcess.StartInfo.FileName = BurnerFilesPath + "mplex.exe";
                                      ConvertProcess.StartInfo.Arguments = "-f 8 -S 0 -M -V -o \"" + strTempFolder + "\\" + FileNamesToBurn[i] + "\" \"" + strTempFolder + "\\" + FileNamesToBurn[i] + "-0.m2v\" \"" + strTempFolder + "\\" + FileNamesToBurn[i] + "-0.mp2 \"";
                                      ConvertProcess.Start();
                                      ConvertProcess.WaitForExit();
                                  }
    
    
                              // Make the DVD files using Config.xml
                              ConvertProcess.StartInfo.FileName = BurnerFilesPath + "dvdauthor.exe";
                              ConvertProcess.StartInfo.Arguments = "-o " + strTempFolder + "\\DVD_Image -x " + strTempFolder + "\\Config.xml";
                              ConvertProcess.Start();
                              ConvertProcess.WaitForExit();
    
                              ConvertProcess.StartInfo.FileName = BurnerFilesPath + "dvdauthor.exe";
                              ConvertProcess.StartInfo.Arguments = "-o " + strTempFolder + "\\DVD_Image -T";
                              ConvertProcess.Start();
                              ConvertProcess.WaitForExit();
     

    samuel337

    Portal Pro
    August 25, 2004
    772
    0
    Melbourne, Australia
    I would suggest letting the process run in the background instead of using WaitForExit like you are now because this will freeze up the UI thread (although the command output will continue to work).

    Add in this line when you setup the ProcessStartInfo object:
    psi.EnableRaisingEvents = true;

    Remember to subscribe to the Exited event handler of the process object (e.g. ConvertProcess). Do not WaitForExit.

    Now when one process has finished, the exited event handler will trigger, and you can load the next one. I'd use an enum to keep track of which step the process is at. Also, make sure you reinstantiate your process object everytime you use it.

    What's wrong with the current code btw (apart from what I've pointed above)? It should run each application one after the other, given you've used WaitForExit.

    Sam

    [/code]
     

    egonspengleruk

    Retired Team Member
  • Premium Supporter
  • June 30, 2005
    250
    0
    samuel337 said:
    I would suggest letting the process run in the background instead of using WaitForExit like you are now because this will freeze up the UI thread (although the command output will continue to work).

    Add in this line when you setup the ProcessStartInfo object:
    psi.EnableRaisingEvents = true;

    Remember to subscribe to the Exited event handler of the process object (e.g. ConvertProcess). Do not WaitForExit.

    Now when one process has finished, the exited event handler will trigger, and you can load the next one. I'd use an enum to keep track of which step the process is at. Also, make sure you reinstantiate your process object everytime you use it.

    What's wrong with the current code btw (apart from what I've pointed above)? It should run each application one after the other, given you've used WaitForExit.

    Sam

    [/code]

    Thanks for that Sam.
    Nothings wrong with the current code....just that it freezes the UI thread as you said. :)

    Egon
     

    egonspengleruk

    Retired Team Member
  • Premium Supporter
  • June 30, 2005
    250
    0
    Found the following example...http://msdn2.microsoft.com/en-us/system.diagnostics.process.exited.aspx

    Cant work out how the process in this example knows to call myProcess_Exited when its finished. How do I add this event handler to my code?

    And your idea with enum's....is that a better way than in the example above ?

    I was thinking my code would become
    Code:
    ConvertProcess.StartInfo.FileName = BurnerFilesPath + "mpgtx.exe";
                                      ConvertProcess.StartInfo.Arguments = "-f -d \"" + FilePathsToBurn[i] + "\" -b \"" + strTempFolder + "\\" + FileNamesToBurn[i] + "\" ";
                                      
                                      ConvertProcess.Start();
                                      //ConvertProcess.WaitForExit();
                                      
                                      while (!eventHandled)
                                      {
                                          Thread.Sleep(SLEEP_AMOUNT);
                                      }

    and eventHandled would be set in

    Code:
        private void myProcess_Exited(object sender, System.EventArgs e)
        {
            eventHandled = true;
        }

    but it never calls this in my code so I get stuck in a forever loop.

    Any ideas?

    Cheers for all your help on this one !

    Egon
     

    Users who are viewing this thread

    Top Bottom