您好,登錄后才能下訂單哦!
這期內(nèi)容當(dāng)中小編將會(huì)給大家?guī)?lái)有關(guān)怎么在Nodejs中調(diào)用Dll模塊,文章內(nèi)容豐富且以專(zhuān)業(yè)的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。
有兩種方案可供選擇:
方案一: 使用node-ffi
方案二: 使用C++編寫(xiě)一個(gè)node addon,通過(guò)LoadLibrary調(diào)用dll
什么是node-ffi?
node-ffi是使用純JavaScript加載和調(diào)用動(dòng)態(tài)庫(kù)的node addon,它可以用來(lái)在不寫(xiě)任何C++代碼的情況下調(diào)用動(dòng)態(tài)鏈接庫(kù)的API 接口。
ffi究竟干了什么?其實(shí)它本質(zhì)上還是一個(gè)編譯后的Node addon,node_modules/ffi/build/Release/ffi_bindings.node, ffi_bindings.node就是一個(gè)addon ffi充當(dāng)了nodejs和dll之間的橋梁。
下面是一個(gè)簡(jiǎn)單的加載dll的demo實(shí)例:
var ffi = require('ffi'); var libpath = path.join(_dirname, '/test.dll'); var testLib = ffi.Library(libpath, { 'start': ['bool', ['bool']] }); testLib.start(true); // true
三、安裝node-ffi
npm install ffi
如果本地沒(méi)有安裝編譯node addon的環(huán)境會(huì)報(bào)錯(cuò),如下圖所示
無(wú)論是使用ffi,還是直接寫(xiě)node addon,都缺少不了編譯node Addon這個(gè)步驟,要編譯node addon,有兩種方法:
1、node-gyp( www.npmjs.com/package/nod … )。
npm install node-gyp
具體安裝參考:github.com/nodejs/node…
總結(jié)來(lái)說(shuō)需要以下四點(diǎn):
python 2.7-3.0版本之間 (推薦裝v2.7,v3.x.x是不支持的)
NET Framework 4.5.1
Visual C++編譯工具 (在windows中是不需要安裝VS,如果自己安裝例如VS2015,導(dǎo)致編譯報(bào)錯(cuò)error MSB4132: The tools version "2.0" is unrecognized. Available tools versions are "4.0".這個(gè)問(wèn)題,說(shuō)明沒(méi)有裝好編譯器,又或者編譯器沒(méi)有被正確地識(shí)別, node-gyp的文檔建議使用npm config set msvs_version 2015, 但是有些機(jī)器即使這樣設(shè)置了也無(wú)效,需要手動(dòng)設(shè)置msvs_version, 應(yīng)該這樣寫(xiě): node-gyp rebuild --msvs_version=2015。如果因?yàn)榘惭b了VS2015導(dǎo)致無(wú)法正常編譯,可直接恢復(fù)到安裝VS之前的還原點(diǎn))
環(huán)境變量配置。(注:python安裝位置需要添加到環(huán)境變量)
2、electron-rebuild( www.npmjs.com/package/ele… )
如果采用electron開(kāi)發(fā)應(yīng)用程序,electron同樣也支持node原生模塊,但由于和官方的node 相比使用了不同的 V8 引擎,如果你想編譯原生模塊,則需要手動(dòng)設(shè)置electron的headers的位置。
electron-rebuild為多個(gè)版本的node和electron提供了一種簡(jiǎn)單發(fā)布預(yù)編譯二進(jìn)制原生模塊的方法。 它可以重建electron模塊,識(shí)別當(dāng)前electron版本,幫你自動(dòng)完成了下載 headers、編譯原生模塊等步驟。 一個(gè)下載 electron-rebuild 并重新編譯的例子:
npm install --save-dev electron-rebuild # 每次運(yùn)行"npm install"時(shí),也運(yùn)行這條命令 ./node_modules/.bin/electron-rebuild # 在windows下如果上述命令遇到了問(wèn)題,嘗試這個(gè): .\node_modules\.bin\electron-rebuild.cmd
詳情請(qǐng)看 electronjs.org/docs/tutori…
這里需要注意nodejs版本問(wèn)題,nodejs平臺(tái)必須跟dll保持一致,同樣是32位或者64位,如果兩者不一致,會(huì)導(dǎo)致調(diào)用dll失敗。
成功安裝ffi模塊之后,就可以開(kāi)始我們下面的ffi調(diào)用dll的實(shí)例應(yīng)用。
四、應(yīng)用舉例
在開(kāi)發(fā)需求中,需要調(diào)用基于C++編寫(xiě)的TCP數(shù)據(jù)轉(zhuǎn)發(fā)服務(wù)的SDK。
首先我們來(lái)看一下dll頭文件接口聲明的代碼如下:
#ifndef JS_CONNECTION_SDK #define JS_CONNECTION_SDK #ifdef JS_SDK #define C_EXPORT __declspec(dllexport) #else #define C_EXPORT __declspec(dllimport) #endif extern "C" { typedef void(*ReceiveCallback) (int cmd, int seq, const char *data); /*設(shè)置讀取數(shù)據(jù)回調(diào)*/ C_EXPORT void _cdecl SetReceiveCallback(ReceiveCallback callback); /* *設(shè)置option */ C_EXPORT void _cdecl SetOption( const char* appKey, const char* tk, int lc, int rm ); /* *創(chuàng)建連接 */ C_EXPORT bool _cdecl CreateConnection(); /*發(fā)送數(shù)據(jù)*/ C_EXPORT bool _cdecl SendData(int cmd, int seq, const char *data, unsigned int len); /*釋放連接*/ C_EXPORT void _cdecl ReleaseConnection(); } #endif
ffi調(diào)用dll模塊封裝,代碼如下:
try { const ffi = require('ffi'); const path = require('path'); const Buffer = require('buffer').Buffer; const libpath = path.join(APP_PATH, '..', '..', '/testSDK.dll'); const sdkLib = ffi.Library(libpath, { 'CreateConnection': ['bool', []], 'SendData': ['bool', ['int', 'int', 'string', 'int']], 'ReleaseConnection': ['void', []], 'SetOption': ['void', ['string', 'string', 'int', 'int']], 'SetReceiveCallback': ['void', ['pointer']] }); module.exports = { createConnection: function(){ sdkLib.CreateConnection(); }, setReceiveCallback(cb) { global.setReceiveCallback = ffi.Callback('void', ['int', 'int', 'string'], function(cmd, seq, data){ cb && cb(cmd, seq, data && JSON.parse(data)); }); sdkLib.SetReceiveCallback(global.setReceiveCallback); }, sendData: function(cmd, seq, data){ data = JSON.stringify(data); sdkLib.SendData(cmd, seq, data, data.replace(/[^\x00-\xff]/g, '000').length, 0); }, releaseConnection: function(){ sdkLib.ReleaseConnection(); }, setOption: function (option) { sdkLib.SetOption( option.appKey, option.tk, option.lc, option.rm ); } } } catch (error) { log.info(error); }
第一步:通過(guò)ffi注冊(cè)dll接口
const sdkLib = ffi.Library(libpath, { 'CreateConnection': ['bool', []], 'SendData': ['bool', ['int', 'int', 'string', 'int']], 'ReleaseConnection': ['void', []], 'SetOption': ['void', ['string', 'string', 'int', 'int']], 'SetReceiveCallback': ['void', ['pointer']] });
ffi.Library方法,第一個(gè)參數(shù)傳入dll路徑,第二參數(shù)JSON對(duì)象配置相關(guān)接口。
key對(duì)應(yīng)dll頭文件中輸出的接口,例如C_EXPORT bool _cdecl CreateConnection();
value array配置參數(shù)類(lèi)型,array[0]注冊(cè)接口函數(shù)返回值類(lèi)型,array[1]注冊(cè)接口函數(shù)傳入形參類(lèi)型。
1、基礎(chǔ)參數(shù)類(lèi)型bool, char, short, int, long等。
2、指針類(lèi)型,需要引入ref模塊,如下:
var ref = require('ref'); var intPointer = ref.refType('char'); var doublePointer = ref.refType('short'); var charPointer = ref.refType('int'); var stringPointer = ref.refType('long'); var boolPointer = ref.refType('bool');
3、回調(diào)函數(shù)指針pointer,可以通過(guò)ffi.Callback創(chuàng)建,如下:
global.setReceiveCallback = ffi.Callback('void', ['int', 'int', 'string'], function(cmd, seq, data){ cb && cb(cmd, seq, data && JSON.parse(data)); }); sdkLib.SetReceiveCallback(global.setReceiveCallback);
回調(diào)函數(shù)參數(shù)類(lèi)型配置與dll接口參數(shù)類(lèi)型配置相同,這里就不多說(shuō)。
這里需要注意一點(diǎn),回調(diào)函數(shù)可能會(huì)被JavaScript垃圾自動(dòng)回收機(jī)制回收,所以我這里是把回調(diào)函數(shù)掛載到全局對(duì)象global上。
第二步:接口調(diào)用
通過(guò)ffi.Library(libpath, {...})注冊(cè)接口,可以直通過(guò)返回的sdkLib對(duì)象調(diào)用對(duì)接的接口。例如:
var bool = sdkLib.CreateConnection(); console.log(bool); // true or false; var cmd = 0, seq = 0, data = {...}; var dataStr = JSON.stringify(data); // JavaScript中文字符長(zhǎng)度在C++中長(zhǎng)度計(jì)算要*3 sdkLib.SendData(cmd, seq, data, data.replace(/[^\x00-\xff]/g, '000').length); global.setReceiveCallback = ffi.Callback('void', ['int', 'int', 'string'], function(cmd, seq, data){ cb(cmd, seq, data && JSON.parse(data)); }); sdkLib.SetReceiveCallback(global.setReceiveCallback);
補(bǔ)充:下面看下NodeJS通過(guò)ffi調(diào)用DLL
第一步建立一個(gè)dll, 提供方法如下
int WINAPI CAM_Open(char *pIn, char* pOut);
第二步安裝ffi (前提已安裝python2.x環(huán)境)
npm install --save ffi
第三步創(chuàng)建測(cè)試文件
var ffi = require("ffi") var DLL = ffi.Library('FaceRecognition.dll', { 'CAM_Open' : ['int', ['string', 'string']] }); var result = DLL.CAM_Open("", ""); console.log(result)
上述就是小編為大家分享的怎么在Nodejs中調(diào)用Dll模塊了,如果剛好有類(lèi)似的疑惑,不妨參照上述分析進(jìn)行理解。如果想知道更多相關(guān)知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。