当前位置:主页 > 查看内容

JS调用C++动态库dll最简demo和问题集锦[收藏版]

发布时间:2021-06-18 00:00| 位朋友查看

简介:目录 ? 前言 正文 常见问题梳理 问题一、*.node is not a valid Win32 application 问题二、Error: Dynamic Linking Error: Win32 error 193 问题三、Error: Dynamic Linking Error: Win32 error 126 问题四、Error: Dynamic Symbol Retrieval Error: Win32……

目录

?

前言

正文

常见问题梳理

问题一、*.node is not a valid Win32 application

问题二、Error: Dynamic Linking Error: Win32 error 193

问题三、Error: Dynamic Linking Error: Win32 error 126

问题四、Error: Dynamic Symbol Retrieval Error: Win32 error 127

实现步骤和极简代码

1. 安装工具库

2. 导入依赖库

3. 导出动态库方法

4. 调用导出方法

结尾


前言

Electron开发过程中,很多时候都会遇到调用C++动态库dll的需求。使用JS调用dll库,听上去都很高大上,JS和C++基本上没有什么交集的两种语言,在这个时候碰出了火花。今天就在Electron的基础上介绍一下这个神奇的使用过程和过程可能遇到的各种问题。前端同学感兴趣的话,欢迎收藏+实践!


正文

不得不说,想实现JS调用C++的dll动态库,是需要借助第三方工具和中间件的。

nodejs有很多相关的工具类,它们都可以轻松实现使用JavaScript加载和调用dll动态库,同时还负责处理跨JavaScript和C的类型转换问题。

类似的插件大致有如下几种:

1. node-ffi-napi

仓库地址:https://github.com/node-ffi-napi/node-ffi-napi?

2. node-ffi

仓库地址:https://github.com/node-ffi/node-ffi


常见问题梳理

先说说可能遇到的问题,文章的最后给出一个极简代码实例。

问题一、*.node is not a valid Win32 application

报错信息:

Error: \\?\G:\project\work\electron-quick-start\node_modules\ffi-napi\build\Release\ffi_bindings.node is not a valid Win32 application.
\\?\G:\project\work\electron-quick-start\node_modules\ffi-napi\build\Release\ffi_bindings.node
? ? at process.func [as dlopen] (electron/js2c/asar.js:140:31)
? ? at Object.Module._extensions..node (internal/modules/cjs/loader.js:1034:18)?

问题截图:?

原因:依赖库不是32位的。

解决:这个问题一般比较常见,因为很多依赖库可能和目标应用类型不一致,大多数情况下都发生在 node_modules 的依赖库中。

处理起来也非常简单,只需要重新 rebuild 即可。

在依赖库中执行命令如下:

node-gyp clean configure build --verbose --arch=ia32

如果还不清楚怎么做,可以参考我之前写的一篇文章——《Electron常见问题 9 - *.node is not a valid Win32 application


问题二、Error: Dynamic Linking Error: Win32 error 193

报错信息:

G:\project\work\electron-quick-start\dll.dll
(node:23644) UnhandledPromiseRejectionWarning: Error: Dynamic Linking Error: Win32 error 193
? ? at new DynamicLibrary (G:\project\work\electron-quick-start\node_modules\ffi-napi\lib\dynamic_library.js:75:11)
? ? at Object.Library (G:\project\work\electron-quick-start\node_modules\ffi-napi\lib\library.js:47:10)
? ? at G:\project\work\electron-quick-start\main.js:81:18
(node:23644) UnhandledPromiseRejectionWarning: Error: Dynamic Linking Error: Win32 error 193
? ? at new DynamicLibrary (G:\project\work\electron-quick-start\node_modules\ffi-napi\lib\dynamic_library.js:75:11)
? ? at Object.Library (G:\project\work\electron-quick-start\node_modules\ffi-napi\lib\library.js:47:10)
? ? at G:\project\work\electron-quick-start\main.js:81:18

问题截图:

原因1. 调用的动态库dll是32位的,而目标模块需要的是64位的。

解决:

重新编译一份64位的dll动态库,问题解决。

如果我们换成了64位的dll动态库,还有这个问题,大概率问题就是dll缺少对应的依赖dll库。

原因2. 缺少依赖库。

解决:

从事windows系统开发的小伙伴都知道,我们一般开发的工具dll库,或多或少都会依赖系统的或者第三方的dll库。这也是dll动态库的优势,可以动态依赖和动态调用。如果想省事儿,我们可以直接把需要的系统或者第三方库,以静态库的形式打包进去,这样拿到哪里就可以用了,大概率不会出现这个问题。所以,我们可以使用depends等工具,查看dll的依赖库是否都全了。


问题三、Error: Dynamic Linking Error: Win32 error 126

报错信息:

(node:17224) UnhandledPromiseRejectionWarning: Error: Dynamic Linking Error: Win32 error 126
? ? at new DynamicLibrary (G:\project\work\electron-quick-start\node_modules\ffi-napi\lib\dynamic_library.js:75:11)
? ? at Object.Library (G:\project\work\electron-quick-start\node_modules\ffi-napi\lib\library.js:47:10)
? ? at G:\project\work\electron-quick-start\main.js:81:18

问题截图:

原因:路径问题,很可能就是没有找需要的dll动态库。

解决:避免出现这个问题的原因,就是尽可能使用绝对路径,避免使用相对路径。当然,如果你可以保证路径没有问题的话,这个是随意的。

因为Electron的调试启动路径和安装后的启动路径是不一样的,这一点需要特别注意。

注意:Electron在开发模式下启动的路径是 node_modules/electron/?目录。?


问题四、Error: Dynamic Symbol Retrieval Error: Win32 error 127

报错信息:

(node:21764) UnhandledPromiseRejectionWarning: Error: Dynamic Symbol Retrieval Error: Win32 error 127
? ? at DynamicLibrary.get (G:\project\work\electron-quick-start\node_modules\ffi-napi\lib\dynamic_library.js:113:11)
? ? at G:\project\work\electron-quick-start\node_modules\ffi-napi\lib\library.js:55:21
? ? at Array.forEach (<anonymous>)

问题截图:

这个问题的产生原因一般是dll有问题。就是说生成的C++的dll动态库有问题,一般是因为没有导出方法的符号,所以调用dll的时候找不到对应的方法。

最简单的原因就是导出函数方法时,没有加?extern "C"

居然,也被我遇到了。。。😢

那么 extern "C" 为什么可以影响导出符号呢?那就需要我们简单介绍一下它的作用。

本质作用就是为了能够正确实现C++代码调用其他C语言代码。

当我们加上 extern "C" 后,会指示编译器将这部分代码按照C语言(而不是C++)的方式进行编译。

由于C++支持函数重载,因此,编译器编译函数的过程中会将函数的参数类型也加到编译后的代码中,而不仅仅是函数名;而C语言并不支持函数重载,因此编译C语言代码的函数时不会带上函数的参数类型,一般只包括函数名。 ?这个功能十分有用处,因为在C++出现以前,很多代码都是C语言写的,而且很底层的库也是C语言写的,为了更好的支持原来的C代码和已经写好的C语言库,需要在C++中尽可能的支持C,因此?extern "C" 就变成了一个必然的选择。

说了那么多,快把自己动态库的方法们加上?extern "C",再重新编译一份吧。

看看是不是问题就解决了。

最后,附上一段代码实例:

#include <stdint.h>

#if defined(WIN32) || defined(_WIN32)
#define EXPORT __declspec(dllexport)
#else
#define EXPORT
#endif

extern "C" EXPORT int sum(int a, int b) {
 return a + b;
}

实现步骤和极简代码

能遇到上面这些问题,也算不容易了。

接下来,介绍一下具体步骤。

1. 安装工具库

安装文章开头介绍的任一工具库,这里以?ffi-napi 为例,具体命令:?

?npm i?ffi-napi

2. 导入依赖库

在代码中增加?ffi-napi 依赖库的引用。

代码:

var?ffi?=?require('ffi-napi')?

3. 导出动态库方法

接下来,就是使用 ffi-napi 导出dll动态库中的需要用到的方法,需要注意的是导出的声明语句要和dll动态库中C++方法的名字、参数表、返回值一致。

这里以一个求和方法 int sum(int a, int b)?为例,代码如下:

var dllPath = path.resolve("cpp.dll");
var dllfuns = ffi.Library(dllPath, {
    'sum': [ 'int', [ 'int', 'int' ] ],
});

4. 调用导出方法

这一步也是简单的,代码如下:

  console.log('=======================================')
  var s = dllfuns.sum(1,2); // 调用方法
  console.log("call c++ dll function sum, result: ", s);
  console.log('=======================================')

代码执行结果:

完美!!!!!!

漂亮~~~~~~

结尾

实现JS调用C++动态库的介绍到此就结束了,是不是超级简单,感兴趣和需要demo的小伙伴欢迎评论留言,一键三连(科普:评论+关注+收藏)也是极好的。

?

;原文链接:https://blog.csdn.net/liuzehn/article/details/115536379
本站部分内容转载于网络,版权归原作者所有,转载之目的在于传播更多优秀技术内容,如有侵权请联系QQ/微信:153890879删除,谢谢!

推荐图文


随机推荐