NodeJS和NW經過ffi調用dll/so動態庫

0x01. 使用的 npm 包

首先要安裝 node-gyp, 用來從新編譯依賴包。node

npm instal -g node-gyp

而後主要用到下面三個包:python

  • node-ffi -- 使用Javascript調用動態庫git

  • ref -- 用來定義數據類型,提供指針功能github

  • ref-array -- 用Buffer來實現C語言中的 array 數據類型web

npm install ffi   //這個命令會同時安裝上 ref、ref-struct
npm instal ref-array

0x02. 測試NODEJS調用

要使用動態庫中的函數,首先要對動態庫裏的函數進行聲明。
好比在 Test.dll 庫中,有兩個函數以下:npm

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']]
});

#規則就是  
'函數名':['返回值數據類型':['參數數據類型',...,'參數數據類型']]

聲明完成後,就能夠進行調用了python2.7

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

這裏用簡單的數據類型,來說解調用動態庫的大體流程。剩下比較複雜的地方在於如何模擬像 指針結構體數組 等比較複雜的數據類型。函數

0x03. 結構體、指針、數組的轉化

1. 結構體

結構體須要用到'ref-struct'這個包。假設有如下結構體:visual-studio

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

相關文章
相關標籤/搜索