客户端有些硬件的接口须要调试,是在电脑上连了一些硬件的设备,好比打印机、扫描仪或者进行串口通讯等等。单靠JS是完成不了了,咱们决定经过把C++或者C#把这些功能打包成Dll,而后在Electron客户端中经过Node调用Dll来实现所须要的功能。node
先简单说一下什么是Dll,Dll是动态连接库文件,也是一种代码库的形式,与静态连接库相比,它是在每次程序运行的时候去调用,而静态连接库指令都会被打包到最后的exe文件里,因此若是函数有什么变化那就须要从新生成exe,那动态连接库就不须要这么作了。生成Dll能够经过VS来完成,能够选择使用C#或者C++开发,C#开发界面的比较方便,若是你的功能须要弹出一些界面,那就要用C#编写相应的Dll。不过这里要注意了,用C#语言编写生成的Dll和用C++语言编写生成的Dll是不同的,经过C#生成的Dll须要.net的开发环境,而C++生成的Dll就没有限制。python
Electron里调用Dll其实就是node调用Dll,刚才说了,生成的Dll不同,那么调用方式也不同。我是用到了这两个模块,ffi和edge,使用ffi调用C++生成的Dll,使用edge调用C#生成的Dll。git
好比我这里有个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
这个模块很是强大,不只能够在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#代码试试。函数
过程老是那么地不顺利,即使知道了语法怎么写也会出现一些问题,总结了下大概是如下几种
在Electron的项目使用edge没法编译 edge是一个原生的模块须要用你当前安装node的版本从新编译,从新编译须要使用node-gyp
,按下面几步执行便可
npm install --global windows-build-tools
.\node_modules\.bin\electron-rebuild.cmd