nwjs ffi dll調用實現方案

nodejs ffi 調用dll 方法&過程

背景

Java 調用dll過程當中 JNI的方式,存在隱患,dll常常掛掉,爲此採用nodejs 調用dll進行封裝

開發環境

  • win7 sp1 + nodejs 0.12.3 + python2.7 + vs2013

1.Win7 sp1 (x64操做系統)javascript

  • Win7系統必定要是sp1的,沒有sp1補丁自行到官網下載,sp1補丁(最好本身有系統盤,親測安裝補丁過程比安裝系統還慢)
  • 若是這個補丁沒有更新是裝不上Visual Studio 2013的,仍是乖乖的用這個版本吧。 (我的使用版本經歷,讓人淚奔 vs2015 —— vs2017 —— vs2013)

2.Visual Studio 2013html

  • 提供基礎的編譯環境,nodejs modules在從新編譯的時候須要依賴它
  • 上面已經說了,老老實實安裝吧!!!

3.Python 2.7.6java

4.nodeJS 0.12.3node

  • 通常dll文件都是32位的,ffi調用時須要使用32位版本的nodejs
  • 下載地址:https://nodejs.org/download/r... 文件是msi格式,直接安裝便可,環境變量自動配好不用管。

5.nwjs 0.12.3python

開始動手

1.打開DOS界面,安裝nw-gyp執行下面的命令:

npm install nw-gyp -g

2.設置vs版本:

npm config set msvs_version 2013 --global (2013是visual studio的版本,你也能夠嘗試其餘版本,我是放棄了)

1.新建一個項目文件夾,建立index.html和package.json文件:
(測試是用的windows系統裏的消息窗口dll文件)c++

<html lang="en">
<head>web

<meta charset="utf-8">
   <meta http-equiv="X-UA-Compatible" content="IE=edge">
   <title>nwjs call DLL</title>
   <meta name="description" content="">
   <meta name="viewport" content="width=device-width, initial-scale=1">

</head>
<body>
<script type="text/javascript">npm

var FFI = require('ffi');
   function TEXT(text){
      return new Buffer(text, 'ucs2').toString('binary');
   }
   var user32 = new FFI.Library('user32', {
      'MessageBoxW': 
      [
         'int32', [ 'int32', 'string', 'string', 'int32' ]
      ]
   });
   var OK_or_Cancel = user32.MessageBoxW(
      0, TEXT('I am Node.JS!'), TEXT('Hello, World!'), 1
   );
   console.log(OK_or_Cancel);

</script>
</body>
</html>json

package.json
{

"name": "test",

"version": "1.0.1",

"main": "index.html",

"webkit":{
windows

"plugin" : true<br>

}

}

注意package.json文件裏須要添加webkit屬性來講明你須要調用第三方包。


2.DOS界面下進入項目文件夾,安裝ffi和ref:

npm install ffi

npm install ref


3.編譯ffi和ref模塊,由於ffi中包含ref因此先編譯ref再編譯ffi,依次的命令以下:

進入'項目目錄node_modulesffinode_modulesref',執行nw-gyp rebuild --target=0.12.3
(0.12.3是你的nwjs版本,若是不是這個版本改成你本身的便可)

進入'項目目錄node_modulesffi',執行nw-gyp rebuild --target=0.12.3


4.最後在你的項目文件夾下將全部文件打包爲zip格式,將zip文件拖進node-webkit目錄下的nw.exe文件上執行便可。


5.看到界面上彈出「I am Node.JS!」說明成功了!

參考:https://cnodejs.org/topic/541...

提示:

1.因爲ffi模塊是爲C語言的dll包服務的,因此在編寫的dll的C++源代碼時必需要有 extern 「C」 來修飾。例如在你的c++代碼裏須要這樣聲明函數纔能有效(在.h文件中聲明時使用):

extern "C" DLLSERVER_API int sumInDll(int n1, int n2);


2.ffi在使用時須要匹配對應的環境,若是是32位dll文件,那麼在安裝nodeJS,python和nwjs都須要用對應的32位版本;若是是64位dll文件,則對應的軟件都須要是64位的;


3.ffi在用的時候仍是挺方便的,只要環境匹配對就能夠。惟一的麻煩是它須要對源dll代碼聲明時進行修改,這個就不如addon一勞永逸了。因此若是引用的dll文件比較多,或者是引入第三方dll文件,ffi的方法就不可取。

遇到問題列表

一、winxp 系統下dll錯誤

nodejs的ffi庫是一個很是好用的調用dll的庫,尤爲是在使用nwjs進行桌面應用開發的時候。
安裝、編譯、使用ffi庫的方法比較簡單,網上也有不少教程,可是當咱們在win7或者更高的Windows系統中編譯好了ffi模塊,開發好了應用後會發如今Windows XP上沒法require咱們的ffi,及時將編譯好的ffi_bindings.node單獨require也沒法使用,require的時候會出現「Error: The specified procedure could not be found」的錯誤。
通過幾天的研究,終於找到了解決方案。在可以正常編譯和引用ffi的Windows系統上,進入ffi文件夾中的src文件夾,找到文件「win32-dlfcn.cc」,並將裏面的地96行和第99行的兩行代碼(我是用的ffi版本爲2.2.0,其餘版本尚未肯定是否是這兩行),對應的代碼應該是:

errorMode = GetErrorMode();

SetErrorMode(errorMode | SEM_FAILCRITICALERRORS);

將這兩行代碼註釋掉,而後在從命令行進入到ffi根目錄,執行「node-gyp rebuild」命令(或者「nw-gyp rebuild」命令,若是想要在nwjs中使用),編譯出來的ffi庫就能夠在Windows XP上正常使用了。

參考文章:https://blog.csdn.net/wuya199...

二、nodejs 讀取中文亂碼問題 (iconv-lite)

var ref = require("ref");
var ffi = require("ffi");
var iconv = require('iconv-lite');
var DLL = new ffi.Library('sample.dll', {
'readData': ['int', ['string', 'string']],
'sendMsg': ['string', ['string', 'string']]
});

module.exports = {

sendMsg: function(sendMsg){
    var maxRTNNameLength = 4096;
    var rtnRef = new Buffer(maxRTNNameLength);
    console.log("send:",sendMsg);
    var rtn = DLL.sendMsg(sendMsg, rtnRef);
    var as_data = iconv.decode(rtnRef, 'GBK');//解碼成utf8.
    var userbuffer = iconv.encode(as_data, 'gbk');//utf8數據編碼成gbk
    var as_data = iconv.decode(rtnRef, 'GBK');//解碼成utf8.
    return as_data;
},

readData:function(){
    var maxIdCardLength = 19;
    var idCardRef = new Buffer(maxIdCardLength);
    var maxNameLength = 31;
    var nameRef = new Buffer(maxNameLength);
    if (DLL.readData(idCardRef, nameRef) == 0) {
        var name = ref.readCString(nameRef, 0);
        var card = ref.readCString(idCardRef, 1);
        return {name: name, card: card};
    }
}

}

通過幾天的努力完成了程序的調用,該遇到的問題基本都遇到了,但願本篇文章對你們有幫助!

相關文章
相關標籤/搜索