创建NodeJS AddOn的方式很多,在NodeJS开发出c/c++ addon with NAPI之后,大家基本上都用NAPI写addon了,最基本的原因就是NAPI可以脱离v8修改的依赖,NAPI对v8中的api进行了封装,不同版本的Node会自动适用v8底层的API变化。
node-ffi-napi是一个开源的module,该模块内部通过nodejs napi加载我们自己写的dll中输出的函数(输出函数必须是extern 'c'的),由于该模块在内部使用了napi,所以我们在下载该模块的时候,会自动对模块进行编译,需要提前安装很多的模块,具体可以参考在不同的系统上怎样编译一个addon。
在使用node-ffi-napi的时候,一般也会使用ref-napi, ref-array-napi, ref-struct-napi,具体这些模块的使用可以参考npm上的readme.
Buffer是NodeJs为管理内存而设计的,Buffer是固定内存长度的byte array,是继承与Javascript 的Uint8Array, 你可以跟JS中的DataView一样去操作Buffer,具体使用可以参考NodeJS网站的说明。
下面介绍一下我在适用ffi-napi和Buffer的几个特殊的例子:
1.dll中的调用约定:
在定义dll输出函数的时候使用extern 'c', 也就是编译用的c规则,如果是extern 'c++'的话,就是用的c++规则,就会有函数重命名的问题;默认使用的是__cdecl,不要使用__stdcall,因为__stdcall会带出函数参数信息,一般自定义的都不会使用__stdcall,只有windows API定义这样,这样不利于动态输入参数。
// api.h
#define DllAPI __declspec(dllexport)
extern "C" {
DllAPI void GetTmpStruct(void* buffer);
}
2.在dll中设置回调函数,在c++代码中调用 typescript中的函数,有些特殊情况是一个node程序调用Addon,在addon里面需要调用回调函数,也就是typescript 的code, 需要怎么处理呢?
下面是addon中C++的code:
typedef void (* JsCallBack)(int status, int extendstatus); //callback
void SetTestCallBack(void* wrapper, JsCallBack pfunc)
{
wrapper* p = static_cast<wrapper*> (wrapper);
p->m_pFuncCallBack = pfunc;
}
代码段中SetTestCallBack是输出函数,在typescript中通过ffi加载调用。JSCallBack是函数定义类型,也就是在typescript中的定义的函数格式要满足上面的条件.
那么在typescript中要怎么定义呢?
import * as ffi from 'ffi-napi'
import * as ref from 'ref-napi'
class Testify{
//this callback must be saved in object, so that it will not be removed by nodejs
private ca