I have been working on a small project that ports Python’s ctypes functionality to Mozilla’s XPCOM system. For those unfamiliar with ctypes, its a Python module that allows developers to declare and call exported methods from binary/shared libraries. Developers can then wrap these binary calls in pure Python.
The JavaScript port, called js-ctypes, will give developers this same kind of functionality in Mozilla’s privileged JavaScript. The idea for the library came after helping many extension developers through the process of building binary (C++) XPCOM components. The story usually went something like this:
- Developer wants functionality not built into the Mozilla platform, but easily supported by the native OS.
- Developer wants to use a 3rd party library in an extension or xul app.
- Developer has methods in native code for performance reasons.
The usual answer to these problems is creating a binary (C++) component to act as a wrapper so the native features can be exposed to JavaScript via XPCOM. However, the process of building binary XPCOM components is significantly harder than JavaScript components. The macros and memory management rules of binary components are harder than JavaScript, but its really the compiler and linker flags, IDL, makefiles and SDK versions that make the process painful. The build process must be repeated for each platform too. For many cases, its just too much work.
The goal of js-ctypes is to allow developers to declare methods in binary libraries and then expose those methods as callable JavaScript functions. Developers can then create pure JavaScript library wrappers around binary libraries – without making binary XPCOM wrappers.
Here is a really simple example of using Window’s native MessageBox call from JavaScript:
const nsINativeType = Components.interfaces.nsINativeType;
function msgbox() {
var library = Components.classes["@mozilla.org/js-ctypes;1"]
.createInstance(Components.interfaces.nsINativeLibrary);
library.open("user32.dll"); // Load the shared Windows DLL
var messageBox = library.declare(
"MessageBoxW", // name of the exported method
nsINativeType.INT32, // return type
nsINativeType.INT32, // parent hwnd (its a Window's thing)
nsINativeType.WSTRING, // Unicode message string
nsINativeType.WSTRING, // Unicode title string
nsINativeType.INT32 // bitflag for buttons to show
);
var ret = messageBox(0, "This is the message", "Msg Title 1", 3);
alert(ret);
// You can reuse the method
var ret = messageBox(0, "This is another message", "Msg Title 2", 3);
alert(ret);
}
The js-ctypes code uses the same libffi library as the Python ctypes module. It is currently known to work on Windows and compiles on Linux, but I haven’t got around to testing it. We need to start the Mac implementation. We also need to add support for struct
and more primitive types.
The code is in SVN here and we have a Bugzilla component too (see bugs, file bug).
Note: This functionality cannot be accessed from JavaScript used in web content. Only JavaScript that runs with chrome privileges (extensions and Firefox UI for example) can use js-ctypes.