如何在Electron中調用Dll

如何在Electron中調用Dll

客戶端有些硬件的接口須要調試,是在電腦上連了一些硬件的設備,好比打印機、掃描儀或者進行串口通訊等等。單靠JS是完成不了了,咱們決定經過把C++或者C#把這些功能打包成Dll,而後在Electron客戶端中經過Node調用Dll來實現所須要的功能。node

Dll類型

先簡單說一下什麼是Dll,Dll是動態連接庫文件,也是一種代碼庫的形式,與靜態連接庫相比,它是在每次程序運行的時候去調用,而靜態連接庫指令都會被打包到最後的exe文件裏,因此若是函數有什麼變化那就須要從新生成exe,那動態連接庫就不須要這麼作了。生成Dll能夠經過VS來完成,能夠選擇使用C#或者C++開發,C#開發界面的比較方便,若是你的功能須要彈出一些界面,那就要用C#編寫相應的Dll。不過這裏要注意了,用C#語言編寫生成的Dll和用C++語言編寫生成的Dll是不同的,經過C#生成的Dll須要.net的開發環境,而C++生成的Dll就沒有限制。python

Node如何調用Dll

Electron裏調用Dll其實就是node調用Dll,剛纔說了,生成的Dll不同,那麼調用方式也不同。我是用到了這兩個模塊,ffiedge,使用ffi調用C++生成的Dll,使用edge調用C#生成的Dll。git

ffi調用Dll

好比我這裏有個ffiTest.dll的文件,裏面有個導出的函數叫作joinStr,就是暴露的方法,給定兩個字符串,而後會返回這兩個參數的拼接結果。注意C++生成的Dll要使用C風格extern 「C」不然可能找不到對應的方法名。github

var ffi = require('ffi');
var path = require('path');

var dllPath = path.resolve('ffiTest.dll');

var lib = ffi.Library(dllPath, {
    'joinStr': ['string', ['string', 'string']],
})

var result = lib.joinStr('hello', 'world');
console.log(result); //打印 helloworld

更詳細的示例能夠參考它的教程ffi.Library裏第二個參數是一個Json結構,key表示是方法名,value示一個數組,數組的第一個參數是返回值類型,第二個參數是方法的列表,若是返回值是空的話,那數組第一個參數應該是void。若是返回值或者參數類型不知道是什麼類型就寫void*。要使用ffi中的類型表示C/C++語言中的類型,對照表以下npm

基本類型
int8        Signed 8-bit Integer
uint8       Unsigned 8-bit Integer
int16       Signed 16-bit Integer
uint16      Unsigned 16-bit Integer
int32       Signed 32-bit Integer
uint32      Unsigned 32-bit Integer
int64       Signed 64-bit Integer
uint64      Unsigned 64-bit Integer
float       Single Precision Floating Point Number (float)
double      Double Precision Floating Point Number (double)
pointer     Pointer Type
string      Null-Terminated String (char *)

常見的C語言類型
byte        unsigned char
char        char
uchar       unsigned char
short       short
ushort      unsigned short
int         int
uint        unsigned int
long        long
ulong       unsigned long
longlong    long
ulonglong   unsigned long long
size_t      platform-dependent, usually pointer size

若是是指針類型,能夠利用ref模塊來表示windows

var ref = require('ref');
var refArray = require('ref-array');

var intPtr = ref.refType('int'); //int*類型
var charPtr = 'hello'; //char*能夠用string表示

//若是是個字符數組
var refArray = require('ref-array');
var charPtrPtr = refArray(ref.types.char, 50); //50個大小的數組

假如參數或者返回值是一個結構體,那就須要藉助ref-struct模塊來表示數組

var ref = require('ref');
var FFI = require('ffi');
var Struct = require('ref-struct');

var TimeVal = Struct({
  'tv_sec': 'long',
  'tv_usec': 'long'
});
var TimeValPtr = ref.refType(TimeVal);
var lib = new FFI.Library(null, { 
    'gettimeofday': ['int', [TimeValPtr, 'pointer']]
});
var tv = new TimeVal();
lib.gettimeofday(tv.ref(), null);
console.log("Seconds since epoch: " + tv.tv_sec);
edge調用Dll

edge這個模塊很是強大,不只能夠在node中編寫C#的代碼也能夠在C#中調用node的代碼,它要求有一個.net4.5或者更高版本的環境。C#編寫的Dll要經過async修飾後才能被node調用,大體像是這樣electron

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TestDll
{
    public class StartUp
    {
        public async Task<object> Invoke(object param)
        {
            return "Hello World!";  
        }
    }
}

這樣會生成一個TestDll.dll的文件,在node中async

var edge = require('edge');
var path = require('path');

var driver = edge.func({
    assemblyFile: path.resolve('TestDll.dll'),
    typeName: 'TestDll.StartUp',
    methodName: 'Invoke'
})

//還能夠這麼寫,var driver = edge.func(path.resolve('TestDll.dll'))
//這麼寫默認方法名就是Invoke,C#中class的名字就是StartUp。若是不一致的話調用就會報錯

driver(null, function(err,result) {
    if (err) {
        throw err; 
    } else {  
        console.log(result);
    }
});

利用edge其實能夠在js直接編寫C#的代碼,那徹底不用多個步驟還要去生成Dll了,可是這個項目裏還依賴了別的Dll,這個語法仍是有點懵,搞清楚後再試試直接寫C#代碼試試。函數

遇到的問題

過程老是那麼地不順利,即使知道了語法怎麼寫也會出現一些問題,總結了下大概是如下幾種

  • win32 error 126 Dll文件的路徑寫錯了,或者Dll有相關的依賴,依賴沒有放在與入口Dll在同一級目錄下
  • win32 error 127 ffi定義的函數名、返回值類型或者參數類型與Dll定義的不一致
  • win32 error 193 Dll與當前的操做系統不匹配,當前系統是64位的Dll是32位的
  • 在Electron的項目使用edge沒法編譯 edge是一個原生的模塊須要用你當前安裝node的版本從新編譯,從新編譯須要使用node-gyp,按下面幾步執行便可

    1. npm install -g node-gyp
    2. 安裝Python2.7 Visual Studio Build Tools 或者VS2017。也能夠從npm上下載npm install --global windows-build-tools
    3. npm config set msvs_version 2017
    4. node-gyp --python 你當前Python安裝的路徑
    5. cd node_modules/edge
    6. node-gyp configure
    7. node-gyp build
    8. 若是以爲麻煩能夠直接使用electron-edge-js就不用本身從新編譯了,若是仍是不行,就再裝一下electron-rebuild而後執行.\node_modules\.bin\electron-rebuild.cmd
相關文章
相關標籤/搜索