采用addon方式
- 构建一个测试dll暴露方法如下,生成DLL文件:
#define API_EXPORT extern "C" _declspec(dllexport)
API_EXPORT int doTest(int a, int b);
#include <node.h>
#include <v8.h>
#include <windows.h>
using namespace v8;
Handle<Value> doTest(const Arguments& args) {
HandleScope scope;
if (args.Length() < 2) {
ThrowException(Exception::TypeError(String::New("Wrong number of arguments")));
return scope.Close(Undefined());
}
if (!args[0]->IsNumber() || !args[1]->IsNumber()) {
ThrowException(Exception::TypeError(String::New("Wrong arguments")));
return scope.Close(Undefined());
}
HINSTANCE hDLL;
hDLL=LoadLibrary("testdll.dll");//加载动态链接库dlldemo.dll文件;
typedef int(*doTest)(int a,int b);//函数指针
doTest test=NULL;
test=(doTest)GetProcAddress(hDLL,"doTest");
if (test)
{
int A=test(args[0]->NumberValue(),args[1]->NumberValue());
Local<Number> num = Number::New(A);
return scope.Close(num);
}
Local<Number> num = Number::New(0);
return scope.Close(num);
}
void Init(Handle<Object> exports)
{
exports->Set(String::NewSymbol("doTest"),FunctionTemplate::New(doTest)->GetFunction());
}
NODE_MODULE(addon, Init)
上述代码中Init方法里绑定方法"doTest"到我们实现的函数doTest。里面用LoadLibrary加载DLL并执行对应方法。
- 编写binding.gyp文件
{
"targets": [
{
"target_name": "test",
"sources": [ "test.cc" ]
}
]
}
- 执行
- node-gyp configure
- node-gyp build
完成编译后会在工程目录下出现build目录
- 用js调用测试
var addon = require('./build/Release/hello');
console.log(addon.add(1, 2));
采用ffi方式
在实际项目中还是采用了ffi,因为对于复杂的结构体、结构体指针等在addon中没有找到清晰的文档说明,而ffi要清楚和简单的多:)
- 添加依赖
var ffi = require('ffi');
var ref = require('ref');
var refStruct = require('ref-struct');
var refArray = require('ref-array');
- 定义结构体
var configClass = refStruct({
param1:ref.types.int,
param2:ref.types.int
});
var strClass = refStruct({
arr:refArray(ref.types.char, 100),
});
略
- 映射DLL中的方法
var DLL = ffi.Library('testdll.dll',{
'doStrings':['string',[ref.refType(strClass)]],
'doString':['string',[ref.refType(strsClass)]],
'doResult':['int',[ref.refType(resClass)]],
'doTest':['int',[ref.refType(configClass)]],
'doParam':['int',[ref.refType(paramClass)]],
'doStruct':['string',[ref.refType(ref.refType(ref.types.void)), ref.refType(structClass)]]
});
其中ref.refType(strClass)表示结构体指针
- 调用方法
var config = new configClass();
config.param1 = 3;
config.param2 = 5;
var res = DLL.doTest(config.ref());
备注:
- 在ffi中ref()表示取地址,而deref()表示取指针所指向的值
- void*采用var buf1 = new Buffer(4);表示分配了一个存储地址的内存;由第一条可知
void** 就是var let ptrBuf = buf.ref(); - 将文件读入到一段内存,如下:
var buf1 = new Buffer(100);
buf1.fill(0);
buf1.write('E:\\test.jpg',0,"ascii");