资讯专栏INFORMATION COLUMN

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

lavnFan / 3863人阅读

摘要:指针和引用假设动态库中有函数如下第二个参数为结构体指针,第三个参数是一个引用。我这里选择的是然后找到,下载替换掉重编译和输入版本号,这里实用的是为或者参考资料通过在中调用动态链接库文件厚颜无耻加上自己的博客

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. 搭建编译环境

安装 Visual Studio 2015

> ? [Windows Vista / 7 only] 需要安装 [.NET Framework 4.5.1](http://www.microsoft.com/en-us/download/details.aspx?id=40773)

安装 python 2.7 (不要装3.x.x,不支持),装完后运行

npm config set python python2.7

设置visualstudio版本

npm config set msvs_version 2015

2. 修改 win_delay_load.cc

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

我这里选择的是 nw14, 然后找到 tools/win_delay_load_hook.cc, 下载替换掉 %APPDATA% pm ode_modules ode-gypsrcwin_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. 参考资料

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

Use Native Node Modules

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

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/80342.html

相关文章

  • 使用Rust + Electron开发跨平台桌面应用 ( 二 )

    摘要:前言在上一篇文章使用开发跨平台桌面应用一中,我们将结合起来,使用编写核心业务逻辑,并编译成库提供给的界面调用,但是在上一篇文章中发现遇到了很多问题,尤其是的版本和编译出来的版本必须要一致,否则会无法调用成功,这就很坑了,所以为了改变这一情况 前言 在上一篇文章使用Rust + Electron开发跨平台桌面应用 ( 一 )中,我们将Rust + Electron结合起来,使用Rust编...

    forrest23 评论0 收藏0
  • nwjs(nodejs)写桌面应用(少儿英语学习项目经验总结)

    摘要:项目背景最近上三年级儿子的英语老是记不住单词,而他们又在上科学课,老师让练打字。打字和英语学习都没太适合小家伙的实际情况,因此就花了一个周末写下了这个项目。题库为文件,存在指定目录中。运行方法全局安装克隆源代码安装依赖库运行项目 项目背景 最近上三年级儿子的英语老是记不住单词,而他们又在上科学课,老师让练打字。打字和英语学习都没太适合小家伙的实际情况,因此就花了一个周末写下了这个项目。...

    lovXin 评论0 收藏0
  • iOS 远端代码下发: 使用 JS 设计 Patch

    摘要:远端代码下发,有什么设计思路一般大家都用用别人的,总不好。老王造了个轮子,我来描述一下。代码,采用打包。苹果自己实现的用到了,这个库老王也使用了,,就是把一个语言暴露出来的接口,能让其他语言来调用。 iOS 远端代码下发,有什么设计思路 ? 一般大家都用 JSPatch? 用别人的,总不好。老王造了个轮子,我来描述一下。 老王 Patch, 挺先进的。JavaScript 代码, 采用...

    yeooo 评论0 收藏0
  • PHP 7.4 前瞻:FFI

    摘要:扩展已经通过,正式成为的捆绑扩展库。第一步,从头文件把主要的数据结构和函数声明复制出来目前不支持预处理器除了和,所以宏定义要自己展开。 FFI扩展已经通过RFC,正式成为PHP 7.4的捆绑扩展库(Bundled Extensions)。 什么是FFI FFI(Foreign Function Interface),即外部函数接口,是指在一种语言里调用另一种语言代码的技术。PHP的FF...

    CompileYouth 评论0 收藏0

发表评论

0条评论

lavnFan

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<