Node.js 调用C++库

前言

使用Node.js去调用C++的库,整理了一些相关资料,方便以后开发少走些弯路。希望对大家也有所帮助。

调用方法和使用技巧

文章主要内容:
https://juejin.im/post/5b58038d5188251b186bc902
本文是对上文的一个补充。

Buffer类

在 ECMAScript 2015 引入 TypedArray 之前,JavaScript 语言没有读取或操作二进制数据流的机制。 Buffer 类被引入作为 Node.js API 的一部分,使其可以在 TCP 流或文件系统操作等场景中处理二进制数据流

TypedArray 现已被添加进 ES6 中,Buffer 类以一种更优化、更适合 Node.js 用例的方式实现了 Uint8Array API。

Buffer 类的实例类似于整数数组,但 Buffer 的大小是固定的、且在 V8 堆外分配物理内存。 Buffer 的大小在被创建时确定,且无法调整。

Buffer 类在 Node.js 中是一个全局变量,因此无需使用 require('buffer').Buffer

常用的buffer方法:

Buffer.alloc(size[, fill[, encoding]])
  • size <integer> 新建的 Buffer 期望的长度
  • fill <string> <Buffer> | <integer> 用来预填充新建的 Buffer 的值。 默认: 0
  • encoding <string> 如果 fill 是字符串,则该值是它的字符编码。 默认: ‘utf8’
    分配一个大小为 size 字节的新建的 Buffer 。 如果 fill 为 undefined ,则该 Buffer 会用 0 填充。
Buffer.from(array)

新增于: v5.10.0

  • array <Array>
    通过一个八位字节的 array 创建一个新的 Buffer 。
// 创建一个新的包含字符串 'buffer' 的 UTF-8 字节的 Buffer
const buf = Buffer.from([0x62, 0x75, 0x66, 0x66, 0x65, 0x72]);

如果 array 不是一个数组,则抛出 TypeError 错误。

Buffer.from(buffer)

新增于: v5.10.0

  • buffer <Buffer> 一个要拷贝数据的已存在的 Buffer
    将传入的 buffer 数据拷贝到一个新建的 Buffer 实例。

例子:

const buf1 = Buffer.from('buffer');
const buf2 = Buffer.from(buf1);

buf1[0] = 0x61;

// 输出: auffer
console.log(buf1.toString());

// 输出: buffer
console.log(buf2.toString());

如果 buffer 不是一个 Buffer,则抛出 TypeError 错误。

Buffer.from(string[, encoding])

新增于: v5.10.0

  • string <string> 要编码的字符串
  • encoding <string> string 的字符编码。 默认: ‘utf8’
    新建一个包含所给的 JavaScript 字符串 string 的 Buffer 。 encoding 参数指定 string 的字符编码。

例子:

const buf1 = Buffer.from('this is a tést');

// 输出: this is a tést
console.log(buf1.toString());

// 输出: this is a tC)st
console.log(buf1.toString('ascii'));


const buf2 = Buffer.from('7468697320697320612074c3a97374', 'hex');

// 输出: this is a tést
console.log(buf2.toString());

如果 string 不是一个字符串,则抛出 TypeError 错误。

相关库介绍

npm install ffi    
npm install ref
npm install ref-array
npm install ref-struct

1.ffi是调用dll动态链接库模块
2.ref扩展了内置的Buffer类,有助于JavaScript进行C编程
3.ref-array 在Buffers之上提供C类型的数组
4.ref-struct 在Buffers之上提供了符合ABI的struct(结构体)实例

C++ enum(枚举) 转JavaScript 对象

C++ enum

  enum Color = {
	  RED, 
	  GREEN, 
	  BLUE
  };
  

方式1:

var Color = {
    RED: 0,
    GREEN: 1,
    BLUE: 2
}
if (Object.freeze) Object.freeze(Color);
//或者使用ES6
const Color = {
    RED: 0,
    GREEN: 1,
    BLUE: 2
}
if (Object.freeze) Object.freeze(Color);

方式2

var Color;
if(Color || (Color={})){
    Color[Color["RED"] = 0] = "RED";
    Color[Color["GREEN"] = 1] = "GREEN";
    Color[Color["BLUE"] = 2] = "BLUE";
}
if (Object.freeze) Object.freeze(Color);

导出函数

引用的库

var ffi = require('ffi');
var ref = require('ref');
var Struct = require('ref-struct');
var refArray = require('ref-array');

函数导出

ffi.Library('要调用的dll', {
   '函数名': ['函数返回值类型', ['函数形参1', '函数形参2'], 
})
//这里的 '函数名' 要跟库中的 '函数名' 保持一致.
ref 中常用的方法
  • ref.types.xxx
    在JavaScript中生成C++中对应的基本类型(http://tootallnate.github.io/ref/#types)

  • ref.refType(Object | String type )
    生成C++中对应的指针,例如生成int类型的指针:ref.refType(ref.types.int)

  • ref.ref(Buffer buffer)
    接受一个Buffer实例并返回一个新的Buffer实例,该实例的大小为“指针”的大小,其数据指向给定的Buffer实例。基本上,创建的Buffer是原始指针的“引用”,相当于以下C代码:

    char *buf = buffer;
    char **ref = &buf;
    
  • ref.deref(Buffer buffer)
    返回:解除引用 Buffer 后返回的值。
    接受一个Buffer实例并尝试“dereference(解引用/解除引用/反引用)”它。也就是说,首先它检查 buffer “类型” 的indirection(解除引用)计数,如果它大于1,那么它只返回另一个Buffer,同时减少一级的indirection。
    当Buffer的indirection值为1时,它会检查buffer.type ,buffer.type应该是一个自己具有get()函数的对象。

    var buf = ref.alloc('int', 6);
    var val = ref.deref(buf);
    console.log(val);
    //6
    
内置简写

ffi中内置了一些简写

ref.types.int => 'int'
ref.refType('int') => 'int*'
char* => 'string'

调用例子:

var dll = ffi.Library( './test.dll', {
    Fun1: ['int', ['string', 'int', 'int']], 
    Fun2: [ref.types.void, ['string', ref.types.int]]
})

如果返回值是一个指针的话,则需要先定义一个指针:

//C++的结构体:
struct 
{
    int a;
    char b;
    double c;
} s1;

//JavaScript中的结构体
var s1=Struct({
	a:'int',
	b:ref.types.char
	c:ref.types.double
})

然后再导出函数:

var dll = ffi.Library( './test.dll', {
    Fun1: [ref.refType(s1), ['string', 'int', 'int']], 
})

参考资料

http://tootallnate.github.io/ref/
http://hax.iteye.com/blog/159332
https://en.wikipedia.org/wiki/Indirection
https://nodejs.org/api/buffer.html#buffer_buffer
https://juejin.im/post/5b58038d5188251b186bc902
https://stijndewitt.com/2014/01/26/enums-in-javascript/

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Node.js可以使用`ffi`模块调用设备驱动的dll动态。`ffi`模块 stands for `Foreign Function Interface`(外部函数接口),它允许Node.js应用程序直接调用动态链接中的C/C++函数。 使用`ffi`模块调用设备驱动的dll动态,首先需要安装`ffi`模块。可以使用npm(Node.js的包管理器)通过以下命令进行安装: ```shell npm install ffi ``` 安装完成后,可以在Node.js应用程序中使用`ffi`模块调用设备驱动的dll动态。首先需要引入`ffi`模块: ```javascript const ffi = require('ffi'); ``` 然后,使用`ffi.Library`方法加载dll动态,并定义要调用的函数: ```javascript const libraryPath = 'path/to/your/device/driver.dll'; const myLibrary = ffi.Library(libraryPath, { 'functionName1': ['returnType1', ['parameterType1', 'parameterType2']], 'functionName2': ['returnType2', ['parameterType3', 'parameterType4']] }); ``` 在上述代码中,`functionName1`和`functionName2`是设备驱动DLL中的函数名,`returnType1`和`returnType2`是函数的返回值类型,`parameterType1`、`parameterType2`、`parameterType3`和`parameterType4`是参数的类型。 接下来,可以通过调用`myLibrary`对象的方法来调用设备驱动DLL中的函数: ```javascript myLibrary.functionName1(parameter1, parameter2); ``` 其中,`parameter1`和`parameter2`是要传递给设备驱动DLL函数的参数。 通过以上步骤,就可以在Node.js应用程序中调用设备驱动的dll动态了。当然,在调用之前,需要确保设备驱动dll动态的路径正确,以及设备驱动dll动态中的函数名、参数类型和返回值类型的定义正确。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值