1 Reply Latest reply on Jan 5, 2011 5:23 PM by jordana309-36

    Calling another program in a nativeProcess

    jordana309-36 Level 1

      I  have a system that encodes videos by using a series of command-line tools. Formally, I had AIR modify a file. That change was detected by Directory Monitor, which would then start the first batch file, which would call a PERL script to mangle the data coming in, which would create another batch file, and then the root batch file starts that running. That batch finally calls the format-specific batch file that actually has the commands for encoding. That calls multiple other programs, taking screenshots, resizing the video, packaging it into an MP4, and so on. I wanted to cut out Directory Monitor (the less extra apps you need installed, the better), and do it all from AIR. Now, I can call the root batch file (the first one), but I can't see the terminal, and for some reason AIR won't let me really call another batch file. I need to call many programs and other batch files, so this isn't going to work. I currently re-rout the output to a <p> tag to show what's going on. I know it's not a display problem, because encoding requires 100% of all my processor, and they are all dead, so...

       

      Anyway, here's my code (except the batch files. Just create two batch files, one that calls the other and use AIR to initiate the first one. It won't call the second).

       

      [CODE]

       

          /* Testing the new NativeProcess */
          function makeItGo()
          {
              // Check if native process is even supported
              if(air.NativeProcess.isSupported)
              {
                  /* We first create a file object and attach it to our executable file. We pass that into a startupInfo object, which will be used to initialize the program. We will include in that our arguments to pass into the native application when it is started. "Native application" means that it's a Windows app, not AIR. We also, need to create a process handle, attach listeners (so we can pass in information and get the output into AIR to play with). Finally, we start the application. */
                  var file = new air.File();
                  //file = file.resolvePath("C:\\Documents and Settings\\me\\Desktop\\app\\folder\\\\TestScript.bat"); // Doesn't work. Cannot start a .bat process.
                  file = file.resolvePath("C:\\WINDOWS\\system32\\cmd.exe");
                  var nativeProcessStartupInfo = new air.NativeProcessStartupInfo();
                  nativeProcessStartupInfo.executable = file;
                  encodeProcess = new air.NativeProcess();
                  // Attach listeners to catch all outgoing data (through STDOUT), and to allow us to give additional input, if desired.
                  encodeProcess.addEventListener(air.ProgressEvent.STANDARD_OUTPUT_DATA, outputHandler); // Listener on STDOUT
                  encodeProcess.addEventListener(air.ProgressEvent.STANDARD_INPUT_PROGRESS, inputHandler); // Triggered by NativeProcess object when STDIN stream is flushed.
                  encodeProcess.addEventListener(air.NativeProcessExitEvent, processExited); // Triggered when the application exits. We need to remove all handles and listeners.
                  // Start the application.
                  encodeProcess.start(nativeProcessStartupInfo);
                  // Create string to pass through as a command to our first batch file, and pass it through.
                  var command = "\"" + applicationRoot + "\\program directory\\TestScript.bat\"\n";
                  encodeProcess.standardInput.writeUTFBytes(command);
              }
              else
              {
                  alert("NativeProcess is not supported!");
              }
          } // End makeItGo()
         
          /* When the application outputs something on STDOUT, we catch that event (the data) in the function below */
          function outputHandler()
          {
              var consoleBox = document.getElementById("consoleOutput");
              var data = encodeProcess.standardOutput.readUTFBytes(encodeProcess.standardOutput.bytesAvailable);
              consoleBox.innerText += data;
          }

       

          /* Whenever input is sent to the console, this function makes sure the new output is shown in the console. Not sure it's needed, but it works with it in. */
          function inputHandler(event)
          {
              outputHandler();
          }
         
          /* This takes commands that we type in, and passes it along. */
          function sendToConsole()
          {
              var inputBox = document.getElementById("consoleInput");
              encodeProcess.standardInput.writeUTFBytes(inputBox.value);
              inputBox.value = "";
              return false;
          }
         
          /* Removes all listeners, closes the process, and removes the AIR handle on the process, allowing it to close. */
          function processExited()
          {
              encodeProcess.removeEventListener(air.ProgressEvent.STANDARD_OUTPUT_DATA);
              encodeProcess.removeEventListener(air.ProgressEvent.STANDARD_INPUT_PROGRESS);
              encodeProcess.removeEventListener(air.NativeProcessExitEvent);
              encodeProcess.closeInput();
              encodeProcess.exit(false); // False means don't force the exit.
          }

       

      [/CODE]

        • 1. Re: Calling another program in a nativeProcess
          jordana309-36 Level 1

          I solved my problem. I'm not sure why I was never able to call another program, but I just created a text string that had a path to my second batch file, and passed that string through on STD_IN. The batch file loaded into CMD simply had a variable set called "startString", containing all parameters needed for opening the batch files I needed. I then ECHOed "Encoding Process Started", because once the START command after that was run, everything was sent via STD_OUT, AIR caught it, and then terminated the tread. Doing it this way simply gave the user the familiar terminal that functioned exactly how they expected. If you care, the batch code I used is this (remember that REM is used to signify a comment in CMD code):

           

          [CODE]

          REM We create this startString to allow for arguments to be added. Just put a space, and the variable after (passed in through AIR). The variable, if it has any spaces, requires quotes either in the variable itself or just right here. The below has no arguments.

          SET startString="%USERPROFILE%\Desktop\DEV CODE\ProjectFolder\BatchFileContainingFolder\BatchName.bat"

           

          REM The below is for AIR, so that it knows the encoding process started. It uses a listener for STDOUT, and that doesn't fire until after the START line has run. No idea why that is exactly, but it is. I add this text so it knows to look for this to cut it's thread running this batch file. This will happen after this batch file starts the CMD process specified in the code below.
          ECHO Encoding process started.

           

          REM START will open a new CMD window, so it will look like it used to, but it will no longer be visible to AIR (as AIR has no handle on the new process thread)
          START CMD /C "%startString%"

          [/CODE]

           

          Then, AIR checks STD_OUT for an instance of "Encoding process started", after which I call a function that severs the thread, exits, releases all listeners and handles, and resets everything as it was before the call.

           

          The main reason I did this was because the batch files also need to be run independently, and I couldn't really have anything in the calling of the program that required AIR or input from it. It's messy, and a hack-around, but it worked.