利用JS-ctypes开发Thunderbird扩展

最近一直在帮人处理Thunderbird不同软件版本下XPCOM注册不成功的问题,就是在一个版本下开发的扩展在其他版本上都不能使用。这里纠结了老久,后来想到了可能是xulrunner-sdk版本不同引起的,所以就有了XPCOM组件开发,发现这样开发扩展太麻烦,毕竟组件完成的工作也就是中间模块,只是用来连接Thunderbird和底层模块的,由于之前也写过COM组件,根据对COM组件的开发经历,突然发现这里完全没必要使用XPCOM组件,一个简单DLL模块就行了,因为对Thunderbird事件的捕获、响应都是用Javascript实现的,我们只需要使用JS调用我们的模块,现在就来介绍一下用JS调用dll的方法:js-ctypes。

MDN上关于js-ctypes解释:

js-ctypes allows application and extension code to call back and forth to native code written in C. C++ support is limited, see bug 505907 for full support. Unlike binary XPCOM components, It allows developers to ship a single binary for use with multiple versions of Firefox.

注意两点:1、js-ctypes只和C libraries交互,不能和C++ libraries交互,如果需要和C++ libraries交互,可以建立中间C libraries。

2、这个是重要的一点,它可以解决XPCOM的版本兼容问题。



要使用js-ctypes,我们必须导入ctypes.jsm模块:

Components.utils.import("resource://gre/modules/ctypes.jsm")


ctypes对象提供一些方法和数据类型。

CType ArrayType(type[,length]); Returns a new CType representing an array data type.
CData cast(data, type); Casts the specified CData object to a new type, returning a new CData object representing the value in the new type.
CType FunctionType(abi, returnType[, argType1, ...]); Returns a new CType object describing a C function.
CData Int64(n);
String libraryName(name); Returns the correct platform-specific filename for a given library name
Library open(libSpec); Opens a library, specified by a pathname
CType PointerType(typeSpec); Returns a CType object describing a new pointer data type.
CType StructType(name[, fields]); Returns a CType object describing a new structure data type.
CData UInt64(n);
使用ctypes.open加载本地DLL,类似LoadLibrary(),windows环境下:

var lib = ctypes.open("user32.dll");

在MAC OS X下:

var coreFoundation = ctypes.open("/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation");

当你停止使用时,使用close(),如果失败,垃圾回收机制会自动关闭对库的引用。

lib.close();



dll导出函数需要使用Library对象的declare()方法进行声明,一旦声明了,函数可以使用标准语法进行函数调用。例如,我们创建DLL,导出函数long Add(long a ,long b);

在js-ctypes中,我们需要对其进行声明:

var add = lib.declare("Add",
                       ctypes.default_abi,
                       ctypes.long,
                       ctypes.long,
                       ctypes.long);

第一个参数是函数名,第二个参数有三种选择:

default_abi Corresponds to cdecl; standard libraries use this ABI. You also use this for all system calls on Mac OS X and Linux.
stdcall_abi Used for calling functions declared with stdcall on Windows. These functions' names are automatically mangled for you by js-ctypes.
winapi_abi Used for calling Windows system functions. These are declared as stdcall on Windows, but do not have mangled names like those used by stdcall_abi above.

后面的参数,分别是函数的返回参数和输入参数,如何返回是void或输入是void,在声明中不用表示。


另外还有两个属性用来查询错误信息:

errno Number The value of the latest system error. Similar to errno in libc, available on all platforms. Cannot be set.
winLastError Number|undefined The value of the latest Windows error. Similar to GetLastError under Windows, available only for Windows. Cannot be set.


内存管理:如果JS代码段中创建了结构体或者数组成员,只要JS对象存在它们所占有的内存将不会被释放。下面的js-ctypes对象会持有对象引用,保持对象存在:

1、用declare()声明的函数或静态数据,它们会保持library对象存在

2、CType变量使CType对象持续存在。

3、在特定情况下,CData变量使CData对象持续存在。例如通过方位结构体成员或者数组成员产生的CData对象会使CData对象持续存在。

注意当使用CData.address()或addressOfElement或contents直接访问CData的内容时,将会隐式产生一个CData对象,但它不能持续存在,可能会被GC自动回收。在使用它之前应该显式的引用,保证所指对象不会被GC回收。



你可能感兴趣的:(js,dll,js-ctypes)