I have a small bootstrapped extension that loads a dll file at startup()
and holds it in a global variable. I don't know exactly how to use this properly maybe you will correct me on this, but I'm more interested in knowing if the functions I use from the dll file can be called asynchronously.
Right now what I'm doing is :
Components.utils.import("resource://gre/modules/ctypes.jsm");
log = function(str) { Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService).logStringMessage(str+'\n'); }
var lib;
var someFunc;
...
function startup(aData, aReason) {
lib = ctypes.open(dllPath);
if(!lib)
{
log("dll load error");
lib = null;
return;
}
else
{
var initDll = lib.declare("Init", ctypes.default_abi, ctypes.long);
var status = initDll();
log("Dll returned " + status);
if(status == ctypes.long(0))
{
someFunc = lib.declare("SomeFunc", ctypes.default_abi, ctypes.long, ctypes.long);
}
}
}
Once I have someFunc
I use it in the code quite often, but the call takes a long time. Is there a way to call it asynchronously? Or to call it in such a way that Firefox doesn't freeze for the duration of the call?
If the external (bound via ctypes
) API isn't itself asyncrhonous, by definition you're not going to be able to call it asynchronously in JavaScript.
The easiest workaround is to use some kind of WebWorker to call the API in a background thread. Seeing as you need to do some privileged stuff, the ChromeWorker APIs fit the bill.
The mechanics of it are:
ChromeWorker
(a.k.a the 'worker')postMessage
to kick off the 'job'ctypes
and make the synchronous call to the external code, and then...postMessage
to the caller (your main code) to say (effectively, "I'm done"). If the external API requires call-specific arguments, you could organise to post those via the first postMessage
. If the external API returns anything significant, you could organise to receive those via the second postMessage
.
All of that will look a bit fiddly, so you'll want to package it into a JavaScript code module; that will allow you to separate the ctypes
stuff from the rest of your code, and you can use createEvent
and dispatchEvent
in the calling thread (inside the module) to make the API seem asynchronous but hide the 'worker' part.