DevelopmentJavascriptOpen SourceProgrammingXRap

Run External Apps using XPCOM Interfaces

By December 4, 2008July 8th, 20144 Comments

I thought it was impossible to run a program outside my XUL app, mainly because of some kind of JavaScript restriction. There are client-side restrictions to protect the file system from being infected from malicious code, however there are some server side solutions, but most of them use ActiveX. Is it possible to run a program in JavaScript? Even a batch file?

Here’s my problem, basically Im using a program called WiX, to create an Application Packager, I create an XML based file (.wxs), and compile it through a program called candle.exe taking it in as an argument.

C:\>candle.exe filename.wxs
C:\>light.exe filename.wixobj

Candle will return a new file with the extension .wixobj, which must then go through a linking program called light.exe in the same fashion. I’m using XUL (Mozilla) to create a program which will pretty much automate most of the tasks, XUL uses JavaScript, can JavaScript run external commands?

After some chatting on IRC, I was directed to the nsIProcess interface, and nsILocalFile.launch(). I actually ended up trying both, however nsIProcess is actually the recommend way to go about this problem, mainly because nsILocalFile.launch() may not work on all platforms.

This is how I used nsIProcess:

function callLight()
{
var getWorkingDir= Components.classes[“@mozilla.org/file/directory_service;1”]

.getService(Components.interfaces.nsIProperties)
.get(“CurProcD”, Components.interfaces.nsIFile);

var lFile = Components.classes[“@mozilla.org/file/local;1”] .createInstance(Components.interfaces.nsILocalFile);

var lPath = getWorkingDir.path + “\\wix-2.0\\light.exe”

lFile.initWithPath(lPath);
var process = Components.classes[“@mozilla.org/process/util;1”] .createInstance(Components.interfaces.nsIProcess);
process.init(lFile);
var wxsPath = inputPath + “\\” + getAppName() + “.wixobj”;
var args = [wxsPath];

process.run(true, args, args.length);
}

getWorkingDir – is of type nsIProperties, and the “CurProcD” basically gets my current working directory, which for my reason is where my wix source files reside

lFile – is of type nsILocalFile, and will hold the file, in my case it will be either candle.exe or light.exe

  • lPath – holds the path to the file which lFile will contain
  • lFile.initWithPath(path) – initalized the nsILocalFile with the parameterized path

process – is of type nsIProcess, is the interface which will represent an executable process

  • process.init(nsILocalFile) – initializes the selected nsILocalFile to a process
  • process.run(blocking, args, arg_count) – Runs the process
    • blocking – is a boolean qualifier, if true will wait for the process to complete before continuing with the program, and if false will continue and let the process run by itself
    • args – is a string array of arguments which may be passed to the executing process
    • arg_count – is the number of arguments being passed

It worked perfectly, the only reason I used the nsILocalFile.launch() was that I didn’t realize that the output file (.wixobj) would end up in the directory which I was executing my XRap program, and not where the source (.wxs) was located. So I had to create a batch file, and use launch() to execute it. It was more code than needed, and created extra files, nsIProcess is much better to work with.

MDC – Running Applications

…Happy Processing!

4 Comments

  • Do candle.exe or light.exe take parameters that allow you to specify where the output should go? I’m sure they must. That might help you to be certain that your script works on all platforms and cut down on the code. Although, if this is a Windows only thing, then nsILocalFile.launch() is fine. In fact, it’s the most reliable way (only way?) on windows to launch batch files.

    Other than CurProcD, there are some other directories that you can locate and use as an output directory:
    https://developer.mozilla.org/en/Code_snippets/File_I%2f%2fO

  • You don’t care about things that don’t run on all platforms — candle.exe/light.exe will also only run on Windows. So use what works on Windows, if it’s easier.

  • Usin strings to build paths is not considered a “best practice” and is not portable between platforms”

    getWorkingDir.path + “\\wix-2.0\\light.exe”

    Typically, you clone a file from the folder and append, like this:

    var file = getWorkingDir.clone();
    file.append(“wix-2.0”);
    file.append(“light.exe”);

    Also, using the .path protperty to create a nsILocalFile is not needed in this case, as the file should support it. Just QueryInterface to nsILocalFile:

    file.QueryInterface(Components.interfaces.nsILocalFile);

    Then pass “file” to the “process.init”

  • Joshua says:

    Re: James Boston
    David Humphrey
    candle.exe and light.exe only take in one parameter, which is the object they will be compiling or linking. Its true that candle.exe and light.exe will only work on the Windows platform, which is why I used nsIProcess, it does the work of creating a batch file, without having to create one.

Leave a Reply