Field Notes from the Workshop · № 210 Development

Run External Apps using XPCOM Interfaces

Joshua Doodnauth Software Engineer · Toronto
December 4, 2008 3 min read 526 words

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!