当前位置: 首页 > 后端技术 > Node.js

如何在Electron中调用Dll

时间:2023-04-03 20:46:21 Node.js

如何在Electron中调用Dll客户端的一些硬件接口需要调试,连接到电脑上的一些硬件设备,比如打印机,扫描仪,或者串口通讯。光靠JS是做不到的。我们决定将这些功能用C++或者C#封装成Dll,然后在Electron客户端通过Node调用Dll来实现需要的功能。Dll类型先简单说一下什么是Dll。dll是动态链接库文件,也是代码库的一种形式。相对于静态链接库,每次程序运行时都会调用,静态链接库指令会被打包到最终的exe文件中,所以如果功能有变化,需要重新生成exe,并且动态链接库不需要这样做。生成Dll可以通过VS来完成。您可以选择使用C#或C++进行开发。C#开发界面更方便。如果你的功能需要弹出一些界面,需要用C#写相应的Dll。不过这里要注意,用C#语言编写生成的Dll和用C++语言编写生成的Dll是不一样的。C#生成的Dll需要.net开发环境,而C++生成的Dll没有限制。Node如何调用Dll在Electron中调用Dll其实就是node调用Dll。刚才说了,生成的Dll不一样,所以调用方式也不一样。我使用了ffi和edge这两个模块,使用ffi调用C++生成的Dll,使用edge调用C#生成的Dll。ffi调用Dll。比如我这里有一个ffiTest.dll文件。有一个名为joinStr的导出函数,它是一个暴露的方法。给定两个字符串,返回这两个参数的拼接结果。注意C++生成的Dll要使用C风格的extern"C",否则可能找不到对应的方法名。varffi=require('ffi');varpath=require('path');vardllPath=path.resolve('ffiTest.dll');varlib=ffi.Library(dllPath,{'joinStr':['string',['string','string']],})varresult=lib.joinStr('hello','world');控制台日志(结果);//printhelloworld更详细的例子可以参考它的教程。ffi.Library中的第二个参数是一个Json结构,key代表方法名,value代表一个数组。数组的第一个参数是返回值类型,第二个参数是方法列表。如果返回值为空,则数组的第一个参数应为void。如果返回值或参数类型未知,写void*。用ffi中的类型来表示C/C++语言中的类型,对照表如下基本类型int8Signed8-bitIntegeruint8Unsigned8-bitIntegerint16Signed16-bitIntegeruint16Unsigned16-bitIntegerint32Signed32-bitIntegeruint32Unsigned32-bitIntegerint64Signed64-bitIntegeruint64Unsigned64-bitIntegerfloat单精度浮点数(float)double双精度浮点数(double)pointerPointerTypestringNull-TerminatedString(char*)常见的C语言类型byteunsignedcharcharcharucharunsignedshortushortunsignedshortintintuintunsignedintlonglongulongunsignedlonglonglonglongulonglongunsignedlonglongsize_t平台相关,通常是指针大小如果是指针类型,可以使用ref模块来表示。varref=require('ref');varrefArray=require('ref-array');varintPtr=ref.refType('int');//int*typevarcharPtr='hello';//char*可以用string表示//如果是字符数组varrefArray=require('ref-array');varcharPtrPtr=refArray(ref.types.char,50);//50个大小的数组如果参数或者返回值是结构体,那么就需要用ref-struct模块来表示varref=require('ref');varFFI=require('ffi');varStruct=require('ref-struct');varTimeVal=Struct({'tv_sec':'long','tv_usec':'long'});varTimeValPtr=ref.refType(TimeVal);varlib=newFFI。库(null,{'gettimeofday':['int',[TimeValPtr,'pointer']]});vartv=newTimeVal();lib.gettimeofday(tv.ref(),null);console.log("自纪元以来的秒数:"+tv.tv_sec);edgecallsDlledge这个模块非常强大,不仅可以在node中编写C#代码还可以在C#中调用node代码,需要.net4.5以上版本环境C#写的Dll被node调用前必须先async修改,大致是这样classStartUp{publicasyncTaskInvoke(objectparam){return"HelloWorld!";这将在节点中生成一个TestDll.dll文件varedge=require('edge');varpath=require('path');vardriver=edge.func({assemblyFile:path.resolve('TestDll.dll'),typeName:'TestDll.StartUp',methodName:'Invoke'})//也可以这样写,vardriver=edge.func(path.resolve('TestDll.dll'))//默认的方法名是Invoke,C#中的类名是StartUp。如果不一致,调用会报错driver(null,function(err,result){if(err){throwerr;}else{console.log(result);}});其实用edge可以直接在js里写C#代码,不需要多步生成Dll,但是这个项目还依赖其他Dll,语法还是有点乱,想通了就直接写C#代码试试出去。遇到的问题总是那么不顺利。即使知道语法怎么写,也会出现一些问题。综上所述,以下win32error126Dll文件路径写错,或者Dll有相关依赖。依赖没有和入口Dll放在同一个目录下。win32error127ffi定义的函数名、返回值类型或参数类型与Dll定义的不一致。win32错误193Dll与当前操作系统不匹配。当前系统是64位的Dll是32位的,不能在Electron项目中使用edge编译。Edge是一个原生模块,需要使用您当前安装的节点的版本重新编译。重新编译需要使用node-gyp。按照以下步骤执行npminstall-gnode-gypinstallsPython2.7和VisualStudioBuildTools或VS2017。也可以从npm下载npminstall--globalwindows-build-toolsnpmconfigsetmsvs_version2017node-gyp--python你当前的Python安装路径cdnode_modules/edgenode-gypconfigurenode-gypbuild如果觉得麻烦,可以使用electron-edge直接-js,不需要自己重新编译。如果还是不行,重新安装electron-rebuild,执行.\node_modules\.bin\electron-rebuild.cmd找不到windows对应的编译工具。这个时候多是下载的vs安装的。该软件包不安装VisualC++构建工具。否则可能会出现以下情况:当前系统可能安装了更高版本的vs,比如vs2019,与你其他模块版本不匹配。这种情况需要修改自定义目录安装的node-gypmsvs版本vs,查看是否包含中文,或者直接选择C盘默认目录安装。最简单的方法是通过执行npminstall--msvs_version=2013覆盖安装。如果在powershell中执行的命令需要设置node-gyp的目录,npmconfigsetnode-gyp="\node_modules\node-gyp\bin\node-gyp.js