• NodeJS和NW通过ffi调用dll/so动态库


     

    0x01. 使用的 npm 包

    首先要安装 node-gyp, 用来重新编译依赖包。

    npm instal -g node-gyp

    然后主要用到下面三个包:

    • node-ffi -- 使用Javascript调用动态库

    • ref -- 用来定义数据类型,提供指针功能

    • ref-array -- 用Buffer来实现C语言中的 array 数据类型

    npm install ffi   //这个命令会同时安装上 ref、ref-struct
    npm instal ref-array

    0x02. 测试NODEJS调用

    要使用动态库中的函数,首先要对动态库里的函数进行声明。
    比如在 Test.dll 库中,有两个函数如下:

    void init(string name, int port);
    
    string hello(int times);

    在 js中进行声明的方法如下:

    var ffi = require('ffi');
    var Test = ffi.Library('Test.dll',{
        'init': ['void',['string','int']],
        'hello': ['string', ['int']]
    });
    
    #规则就是  
    '函数名':['返回值数据类型':['参数数据类型',...,'参数数据类型']]
    

    声明完成后,就可以进行调用了

    Test.init('COM1', 9300);
    Test.hello(5);

    这里用简单的数据类型,来讲解调用动态库的大致流程。剩下比较复杂的地方在于如何模拟像 指针结构体数组 等比较复杂的数据类型。

    0x03. 结构体、指针、数组的转化

    1. 结构体

    结构体需要用到'ref-struct'这个包。假设有以下结构体:

    typedef struct {
        byte UID[16];       /*餐盘标签 UID,16 进制*/
        byte UType[6];      /*餐盘类型,10 进制*/
        int ProdNo;         /*菜品编码,10 进制*/
        int ProdPrice;      /*菜品价格,价格以分为单位,10 进制*/
    } DishInfo;

    int类型的好办,可以直接使用 ref包里含有的类型 ref.types.int
    UIDUType是两个bype类型的数组,需要使用ref-array进行模拟。

    var refStruct = require('ref-struct');
    var refArray = require('ref-array');
    
    var DishInfo = refStruct({
        'UID': refArray('byte', 16),
        'UType': refArray('byte', 6),
        'ProdNo': ref.types.int,
        'ProdPrice': ref.types.int
    });

    2. 指针和引用

    假设动态库中有函数如下, 第二个参数为结构体指针, 第三个参数是一个int 引用。

    int Read(int port, DishInfo * pInfo, int &Count);

    在声明函数的时候,就需要指明指针和引用的数据类型。示例如下:

    var ffi = require('ffi');
    var ref = require('ref');
    var refStruct = require('ref-struct');
    var refArray = require('ref-array');
    
    var DishInfo = refStruct({
        'UID': refArray('byte', 16),
        'UType': refArray('byte', 6),
        'ProdNo': ref.types.int,
        'ProdPrice': ref.types.int
    });
    
    //数据类型
    var intPointer = ref.refType('int');
    var DishInfoArrType = refArray(DishInfo);  //定义了DishInfo数组类型
    
    var Test = ffi.Library('Test.dll',{
        'init': ['void',['string','int']],
        'hello': ['string', ['int']],
        'Read': ['int', ['int', DishInfoArrType, intPointer]]
    });
    
    //实例化
    var count = ref.alloc('int');
    var DishInfoArr = DishInfoArrType(3);
    
    Test.Read(11, DishInfoArray, count);
    
    //使用deref()获取引用的实际值
    var actualCount = count.deref();

    0x04. NW 适配

    使用NodeJS直接调用没问题后,就可以使用 node-gyp 编译适配 NW 的包了, 这里只说明window环境下的使用方法。

    1. 搭建编译环境

    1. 安装 Visual Studio 2015

      > ? [Windows Vista / 7 only] 需要安装 [.NET Framework 4.5.1](http://www.microsoft.com/en-us/download/details.aspx?id=40773)
      
    2. 安装 python 2.7 (不要装3.x.x,不支持),装完后运行

      npm config set python python2.7
    3. 设置visualstudio版本

      npm config set msvs_version 2015

    2. 修改 win_delay_load.cc

    打开 Github - nw.js repository, 然后切换自己使用的nw 版本分支。
    nwjs选择分支

    我这里选择的是 nw14, 然后找到 tools/win_delay_load_hook.cc, 下载替换掉 %APPDATA%\npm\node_modules\node-gyp\src\win_delay_load_hook.cc

    3. node-gyp 重编译 ffi 和 ref

    # --target 输入nw 版本号,这里实用的是 v0.14.3, arch为 ia32 或者 x64
    
    cd node_modules/ffi
    node-gyp configure --target=0.14.3 --arch=ia32
    node-gyp build
    
    cd node_modules/ref
    node-gyp configure --target=0.14.3 --arch=ia32
    node-gyp build
    

    0x05. 参考资料

    1. 通过ffi在node.js中调用动态链接库(.so/.dll文件)

    2. Use Native Node Modules

    3. 厚颜无耻加上自己的博客 XD

  • 相关阅读:
    A10 React+AntDesign 组件、父子组件通信、defaultProps、propTypes
    A09 React+AntDesign 模块封装,可供所有组件使用(以对todolist的小优化为例)
    A08 React+AntDesign todolist小项目(下)
    A07 React+AntDesign todolist小项目(上)
    A06 React+AntDesign 表单详解
    A05 React+AntDesign 事件对象、键盘事件、表单事件、类似vue的数据双向绑定
    A04 React+AntDesign 方法、事件、获取数据、改变数据、改变this指向
    A03 React+AntDesign 初识、目录结构、数据绑定、属性绑定、引入图片、循环数组
    泛型学习
    PowerDesigner16.5汉化破解版安装教程(含安装文件、汉化包、破解文件)
  • 原文地址:https://www.cnblogs.com/onesea/p/15874916.html
Copyright © 2020-2023  润新知