node-ffi调用C++编译的动态链接库踩坑记录
前言
提示:以下是本篇文章正文内容,下面案例可供参考
一、安装相关依赖
旧版node-ffi不支持高版本的node环境,其他博主也有详细介绍,我就不再赘述了,现在使用V12以上的node版本需要用到ffi-napi
以及相关的库,由于该库需要使用到node-gyp
进行编译所以需要提前安装好相关环境,node-gyp
的安装可以参考这几篇文章nodeffi入门到放弃, electron使用nodeffi
安装好node-gyp的环境以后现在安装ffi-napi相关的库,官方仓库github
npm install ffi-napi
npm install ref-napi
npm install ref-napi
npm install ref-array-napi
二、使用步骤
1.准备好动态链接库
使用Viasual Studio 2017新建一个dll的项目
创建好项目以后就会得到一个默认的这样的文件
然后分别在头文件pch.h
和源文件pch.cpp
里面添加测试代码
// pch.cpp
int funAdd(int a, int b)
{
return (a + b);
}
// pch.h
extern "C"
{
__declspec(dllexport) int funAdd(int a, int b);
}
别忘记按住Ctrl + s
保存代码
然后编译成dll文件
注意:编译的时候默认编译成64位的就行了
1.引入库
在项目中新建一个index.js
文件和一个dll
文件夹(存放刚刚编译的dll文件)
index.js代码如下(示例):
const ffi = require('ffi-napi');
const ref = require('ref-napi');
const ArrayType = require('ref-array-napi');
const path = require('path');
function testDll(){
const dll = './dll/DLL4.dll';
const filePath = path.resolve(dll);
const lib = new ffi.Library(filePath, {
'funAdd': // 声明这个dll中的一个函数
[
'int', ['int', 'int'], // 用json的格式罗列其返回类型和参数类型
],
});
const result = lib.funAdd(1, 2);
console.log(result);
}
然后在控制台执行
node index.js
如果没有报错那就恭喜你以及可以成功调用dll文件了
如果遇到了类似这样的报错,Dynamic Linking Error: Win32 error 193
,那就是你的动态链接库可能是32位的而你的操作系统是64位的。如果想测试复现这个错误,可以在上面的介绍中将编译的配置项改为x86
然后重新编译就可以得到一个32位的dll文件。
请查看相关博客描述常见的错误信息,在这里我也不做赘述了,Electron——常见动态链错误
node-ffi调用dll踩坑记录
dll查看器的使用
在调试过程中如果遇到了Dynamic Linking Error: Win32 error 127
的报错,我遇到了三种情况
- 你在
new ffi.Library
的参数里面写的函数名与C++代码的函数名不一致,比如C++里面是funAdd
函数你写成funadd
- 也可能是函数的参数类型错误,比如funAdd函数的参数类型是
int
你写成double
- 还有一种就是动态链接库里面还引用了别的动态链接库,但是你本地的电脑环境里面没有这个文件引用的别的dll文件
第三种情况就可以使用dll查看器检查你的dll文件是否有问题,参考Win10 查看 DLL 中的函数
我会将这个dll查看器上传到我的资源我的资源中,方便大家下载,免费的哦
把工具下载好了以后,解压文件,找到DependenciesGui.exe
这个文件双击运行
可以正常执行的dll文件应该是一下图片中的内容
左侧是你的dll文件依赖的一些其他dll文件的文件树,右侧就是dll文件里面函数名,地址等信息
那我们现在打开一个有问题的dll文件,(这个dll文件是通过Cmake的方式编译的,这个dll文件还依赖了mingw的dll文件)
找到报错的dll文件
然后我找了报错的dll文件
所以报错的原因已经找到了,就是nodejs在调用A这个dll文件的时候,A还依赖了其他的dll文件,但是你的系统里面找不到A依赖的文件所以导致报错,至于报错信息为什么是Dynamic Linking Error: Win32 error 127
还有待研究,估计得看源码。
由于该动态链接库是Cmake编译的,而且在编译的时候选择了动态库的形式,所以把这个编译出来的dll库放到其他环境可能就无法运行。最好的解决办法就是编译成静态库,简单的说就是把你编译的目标dll文件所依赖的dll文件一起打包,就像克隆别人的代码仓库,把别人的代码仓库里面的node_modules
包一起克隆。如何编译静态库 请参考Clion创建和调用静态库
__declspec(dllexport)关键字
还有一个关键的地方就是在.h
的头文件中函数声明前面添加 __declspec(dllexport)
关键字,其实不添加这个关键字编译出来的dll文件也可以正常运行,只不过在dll查看器里面看不到你声明的函数,因为头文件不参与编译。
下面放两张参考图
总结
总之踩了各种各样的坑终于把Cmake编译的dll文件跑起来了,踩坑的原因也是因为自己对C++不熟悉,对Cmake不熟悉,对编译原理不熟悉,填坑的时候耗费了大量的时间去查资料。希望对大家有帮助。最好来个一键三联鼓励一下,以后我会多多分享开发中常见的填坑技巧。谢谢大家🎉✨