Node调用C/C++ DLL

采用addon方式

  1. 构建一个测试dll暴露方法如下,生成DLL文件:
#define API_EXPORT extern "C" _declspec(dllexport)

API_EXPORT int doTest(int a, int b);
  1. 编写对应的addon文件test.cc
#include 
#include 

#include 

using namespace v8;

Handle 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 num = Number::New(A);
     return scope.Close(num);
  }

  Local num = Number::New(0);
  return scope.Close(num);
}

void Init(Handle exports) 
{
  exports->Set(String::NewSymbol("doTest"),FunctionTemplate::New(doTest)->GetFunction()); 
}

NODE_MODULE(addon, Init)
 
  

上述代码中Init方法里绑定方法"doTest"到我们实现的函数doTest。里面用LoadLibrary加载DLL并执行对应方法。

  1. 编写binding.gyp文件
{
  "targets": [
    {
      "target_name": "test",
      "sources": [ "test.cc" ]
    }
  ]
}
  1. 执行
  1. node-gyp configure
  2. node-gyp build
    完成编译后会在工程目录下出现build目录
  1. 用js调用测试
var addon = require('./build/Release/hello');

console.log(addon.add(1, 2)); 
采用ffi方式

在实际项目中还是采用了ffi,因为对于复杂的结构体、结构体指针等在addon中没有找到清晰的文档说明,而ffi要清楚和简单的多:)

  1. 添加依赖
var ffi = require('ffi');
var ref = require('ref');
var refStruct = require('ref-struct');
var refArray  = require('ref-array');
  1. 定义结构体
var configClass = refStruct({
	param1:ref.types.int,
	param2:ref.types.int
});

var strClass = refStruct({
	arr:refArray(ref.types.char, 100),
});
略
  1. 映射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)表示结构体指针

  1. 调用方法
var config = new configClass();
config.param1 = 3;
config.param2 = 5;

var res = DLL.doTest(config.ref());

备注:

  1. 在ffi中ref()表示取地址,而deref()表示取指针所指向的值
  2. void*采用var buf1 = new Buffer(4);表示分配了一个存储地址的内存;由第一条可知
    void** 就是var let ptrBuf = buf.ref();
  3. 将文件读入到一段内存,如下:
var buf1 = new Buffer(100);
buf1.fill(0);
buf1.write('E:\\test.jpg',0,"ascii");

你可能感兴趣的:(c,node)