nodejs ffi调用C++dll动态库 ffi调用语法
ffi介绍:
node-ffi是一个用于使用纯JavaScript加载和调用动态库的Node.js插件。它可以用来在不编写任何C++代码的情况下创建与本地DLL库的绑定。同时它负责处理跨JavaScript和C的类型转换。
node-ffi连接了C代码和JS代码, 通过内存共享来完成调用, 而内部又通过ref,ref-array和ref-struct来实现类型转换。
一、环境安装、配置
1、以管理员权限打开cmd,输入快捷命令:npm install --global --production windows-build-tools
这期间可能会遇到visual studio(C++工具包)安装不成功的情况:
这种情况下可以使用离线安装的方式(通过以下链接下载离线安装包):
https://pan.baidu.com/s/1Nh7cCrqyroEMH90HUYbvfw 提取码:5251
直接安装:
安装完成之后查看python是否安装成功:
这说明安装成功,安装成功之后将python的路径添加到环境变量中:
2、安装.net环境地址(可以选择4.6.2包)
.NET SDKs downloads for Visual Studio
3、安装上述各环境之后就可以安装ffi了,我这边安装的ffi版本是2.3.0的,使用命令
cnpm install ffi@2.3.0,相对应类型转换的插件版本如下:
"ffi": "^2.3.0",
"ref": "^1.3.5",
"ref-array": "^1.2.0",
"ref-struct": "^1.1.0",
4、安装上述环境的过程中遇到了很多问题,捣鼓了很久才把整个环境安装好,环境安装好之后调用动态库的过程也遇到很多问题,下面记录下自己在安装和调用的过程中遇到的一些问题:
(1)报语法错误:
上面的截图说是啥语法错误,在网上找了很多资料,很多说是因为nodejs版本高了的问题,于是我将nodejs版本降低,降低到了v11.10.0,然后再安装,最后成功了:
(2)font.scss报错:
上面截图的错误可以通过提示重新安装一遍sass,命令如下:
npm rebuild node-sass
(3)Error:Cannot find module 'ffi'
上面的提示需要重新安装一遍ffi
(4)Error: A dynamic link library (DLL) initialization routine failed
上面报错问题需要执行下面的命令重新rebuild:
1、npm config set python "C:\Python27\python.exe"
2、npm config set node_gyp "C:\Users\10376\AppData\Roaming\npm\node_modules\node-gyp\bin\node-gyp.js"
3、重新编译electron:./node_modules/.bin/electron-rebuild
4、.\node_modules\.bin\electron-rebuild.cmd
(5)调用动态库时报各种编码错误:
Uncaught Error: Dynamic Linking Error: Win32 error 126
DLL引用的路径错误,检查下DLL的路径是否正确(因为项目中调用的动态库比较多,出现有的用下面的方式写可以正常调用,但是有的动态库必须放在本机安装的nodejs的目录下,具体原因没摸清楚,猜测是因为C++打包或配置的问题,不同的包引入方式不同)
// 正确示例
let DllA = path.resolve(__dirname, '../../../xxx/xxxx.dll')// 生产环境
if (process.env.NODE_ENV !== 'development') {DllA = path.resolve(__dirname, '../../../../xxx/xxx' + arch + '.dll')DllB = path.resolve(__dirname, '../../../../xxx/xxxx.dll')
}
Uncaught Error: Dynamic Linking Error: Win32 error 193
DLL位数不对,根据系统来确定使用x86还是x64,可通过os
进行判断引入相应的DLL
// 正确示例
const arch = os.arch() === 'x64' ? 'x64' : 'x86'
let DllA = path.resolve(__dirname, '../../../xxx/xxx' + arch + '.dll')
if (process.env.NODE_ENV !== 'development') {DllA = path.resolve(__dirname, '../../../../xxx/xxx' + arch + '.dll')
}
Uncaught Error: Dynamic Linking Error: Win32 error 127
DLL没有对应的函数或函数定义错误,可以使用函数查看器
进行查看
DLL错误,比如系统的一些DLL可以直接进行引用或者还需要引用其他的DLL文件(如: 引入A,但是A需要引入B)
函数查看器下载地址
// 正确示例
const User32 = ffi.Library('user32.dll', {GetTopWindow: ['long', ['long']],GetWindowThreadProcessId: ['int', ['long', 'int']],GetForegroundWindow: ['long', []],IsHungAppWindow: ['bool', ['long']]
})
二、ffi调用C++动态库语法详解
变量类型:C语言中有4种基础数据类型(整型 浮点型 指针 聚合类型)
1、整形、字符型都有分有符号和无符号两种。
在不声明unsigned时,默认为signed型
ref中unsigned会缩写成u,如uchar对应unsigned char
浮点型中有float double long
2、项目中使用:
(1)插件引入
(2)调用C++方法初始化
C++定义的原始方法如下:
1、初始化第三方
int BS_Init3(char *IP, short port, unsigned short SysCode, unsigned short TerminalNo)
2、初始化读卡器
int BS_CRInit()
3、关闭读卡器
bool BS_CRClose()
4、快速读卡号
int BS_FastGetCardNo(unsigned int *CardNo)
5、读卡,返回余额和学号
int BS_ReadCard(int *Balance, char *StudentCode)
6、消费,传入消费金额TranAmt(以分为单位的正整数),返回卡片消费后的余额Balance
int BS_Consume(int TranAmt, int *Balance)
上述中new ffi.Library就是ffi调用C++的方法,第一个参数是动态库的位置,第二个参数是调用动态库的方法,类型通过ref相关插件进行转换。
主要需要注意的就是4、5、6方法中的指针类型,CardNo、Balance和StudentCode需要转换成指针类型,调用的时候会通过这个变量将值写入返回给我们。
(3)方法调用
调用1初始化方法,只需要将值传入看返回值是否初始化成功就可以了
调用2方法:
调用3方法:
调用4方法,这里需要注意的就是CardNo,它是个指针类型,需要通过ref.alloc()方法定义一个变量,用于接收动态库给的值,拿到值之后通过ref.deref()的方法转换一下,其实ref就相当于一个语言转换器,先将我们的语言转换成C++可以识别的,拿到值之后再转换成js可以识别的。
调用5、6,这里与上面不用的是*char类型的处理方式
3、项目中语法使用过程中遇到的问题记录(复杂结构体的调用)
结构体指针类型,结构体只有输入值的可以正常调用成功,但是当结构体中有些字段需要前端传递值,有些字段是C++动态库返回的值的情况下,每次调用的都不成功,具体如下:
结构体定义:
结构体初始化:
结构体调用:
上述调用的过程中每次返回给我的错误信息都是交易额错误,也就是二进制的-0000000001怎么转换也传不过去,问了java的开发人员都说没有这种值得处理方式,其实在C++中就是将这个值塞到内存地址中,然而我在nodejs中用啥方法也不行,最后迫于无赖只能让动态库得开发人员重新封装,将调用得方法传参改得简洁一点。
如果有大佬实现过这种复杂得结构体调用可以一起探讨!!!
nodejs ffi调用C++dll动态库 ffi调用语法相关推荐
- java调用c so动态库_jni 调用C动态库dll/so
http://hi.baidu.com/fengying765/blog/item/7081113e5fde53e555e7233f.html 作为主调方的Java源程序TestJNI.java如下. ...
- Node.js 调用 dll动态库 以华旭身份证阅读器为例
需求来源 由于使用Electron使用开发桌面端,同时也需要连接硬件设备,单纯使用js方法无法完成,需要通过Node调用dll动态库方式完成. 版本说明: node v12.18.3 (32位) np ...
- C++中.lib静态库、.dll动态库的生成及调用2
关于动.静态库的介绍及静态库的生成及调用参见:C++中.lib静态库..dll动态库的生成及调用<1>,本文主要介绍基于VS2015平台的动态库dll的生成及调用方法. 一.动态库的生成 ...
- C++中.lib静态库、.dll动态库的生成及调用1
一.前言 1.动态链接库(dll)与静态链接库(lib): 动态链接库(dll)是一个可以被其他应用程序共享的程序模块,其中封装了一些可以被共享的例程和资源.在链接步骤中,连接器将从库文件取得所需的代 ...
- JNA框架调用dll动态库(给你整得明明白白)
java调用dll动态库的方法,总的有三种:JNI.JNA.JNative.其中JNA调用DLL是最方便的.网上文章一大堆,我就不废话了. 使用JNA框架调用DLL动态库,步骤如下: 一.环境准备 1 ...
- java 动态库_java调用dll动态库文件的一般总结
前一段时间,在项目需求中,需要调用一下第三方的动态库文件,下面是本人一些尝试的经历. 首先需要明白的是,在java中是不能直接调用动态库文件的,因为动态库文件是使用c或是c++编写的,作为一种跨 ...
- C#调用C/C++动态库dll异常:对 PInvoke 函数调用导致堆栈不对称问题
结论:如果你是用C#调用C的动态库,如果出现"对 PInvoke 函数调用导致堆栈不对称问题",建议优先调整CallingConvention的值,建议改为CallingConve ...
- C#总结:C#调用C++的动态库Dll遇到的问题[动态库调用/结构体指针调用/union共同体定义]
记录使用C#调用C++的生成的DLL手柄键盘驱动库包括****.sys(驱动文件)和****.dll(库文件)的全部问题. C#调用C++的库有两种:静态调用和动态调用 静态调用,使用.net 提供的 ...
- C# VC6调用VC6的动态库DLL
C# VC6调用VC6的动态库DLL 一 VC创建动态库 1. DLL的创建 启动VC6.0, 新建一个"Win32 Dynamic-Link Library"工程,选择" ...
- Windows系统下通过JNI调用dll动态库的实现
目的:java代码使用jni获取数据 工具: eclipse + Microsoft visual studio (c++) 业务代码: Java代码业务实现: package com.weip.jn ...
最新文章
- Service Mesh — Overview
- Appium+PythonUI自动化之webdriver 的三种等待方式(强制等待、隐式等待、显示等待)
- 差分进化算法_基于差分进化的水泥烧成系统动态优化算法
- JavaScript正则表达式的坑很深
- (二)线程--通过委托异步调用方法
- ActiveMq工作笔记003---SpringBoot集成ActiveMq_随时更新
- iirf有时有效,有时返回404错误的解决方法
- bzoj 2555: SubString
- c语言getch函数_在C / C ++中使用getch()函数
- qq手机令牌 for android3.3 官方安装版,原QQ安全助手|QQ手机管家 for Android 安卓版v3.3.0 - PC6安卓网...
- vbs基础教程(1)
- 中文文本情感分析:基于机器学习方法的思路
- google 常用的技术搜索关键词
- stata陈强:第四章 stata操作基础
- 4g网络什么时候淘汰_4g网络手机。什么时候淘汰
- CVPR2020(Enhancement):论文解读《Zero-Reference Deep Curve Estimation for Low-Light Image Enhancement》
- C语言----白细胞计数
- OpenGL(12)GL库API
- 关于app运营的这几个考核指标你不能不了解!
- 有关stm32单片机外部低速晶振LSE32.768k注意事项;RTC_WaitForSynchro()卡死;