正如 Node.js介绍4-Addon 里说的,让JavaScript调用c++代码有三种方法:

1.在子进程中调用C++程序

 

2.调用C++的dll

参考 关于在electron中调用C++动态库的经验总结

 

3.使用addon(实际上addon也是一个动态链接库)

参考 Node.js v14.8.0 文档 C++ 插件

参考 Electron & C++ 快速开发桌面Web "混合"应用

参考 【electron-vue】在electron中调用Nodejs生成的c++插件

 

这里选用第二种来实验

安装

1、安装 node-gyp 参考 安装node-gyp

由于node程序中需要调用一些其他语言编写的 工具 甚至是dll,需要先编译一下,否则就会有跨平台的问题

npm install node-gyp -g

2、安装 ffi

是一个Node.js插件,用于使用纯JavaScript加载和调用动态库。它可以用来创建到本机库的绑定,而无需编写任何C ++代码

另:node -ffi弃用了,改为了ffi。

npm install ffi --save

我本地是有安装vs和python环境的

 

安装后报错

error C2660: “v8::Value::BooleanValue”: 函数不接受 0 个参数

error C2660: “v8::Value::Uint32Value”: 函数不接受 0 个参数

error C2661: “v8::Object::Set”: 没有重载函数接受 2 个参数

electron 调用mysql electron 调用dll方法_API

当我node版本是v14.8.0的时候,会报错,看了github上很多类似的问题,很多人都反映说将node降级就可以。

卸载node,安装v11.10.0。(我好像成功了!!!!)

electron 调用mysql electron 调用dll方法_python_02

 

 nodejs调用系统dll

testdll.js 

const ffi = require("ffi");
const User32 =  ffi.Library('user32', {
                'GetWindowLongPtrW': ['int', ['int', 'int']],
                'SetWindowLongPtrW': ['int', ['int', 'int', 'long']],
                'GetSystemMenu': ['int', ['int', 'bool']],
                'DestroyWindow': ['bool', ['int']]
            })
console.log(User32.GetWindowLongPtrW);

终端输入,回车

node testdll.js

electron 调用mysql electron 调用dll方法_Dynamic_03

 

electron 调用自己生成的dll

参考 Electron中使用Node-ffi调用DLL 

1、报错 was compiled against a different Node.js version using

electron 调用mysql electron 调用dll方法_python_04

 

安装electron-rebuild

npm install --save-dev electron-rebuild

执行rebuild

"./node_modules/.bin/electron-rebuild.cmd"

下图是多次执行后的结果 

electron 调用mysql electron 调用dll方法_API_05

执行rebuild报错

electron 调用mysql electron 调用dll方法_electron 调用mysql_06

设置python路径(D:\python\2.7.13.1_64bit\python-2.7.13.amd64\python.exe改成自己python路径)

npm config set python D:\python\2.7.13.1_64bit\python-2.7.13.amd64\python.exe

rebuild成功

electron 调用mysql electron 调用dll方法_API_07

2、报错 Error: Dynamic Linking Error: Win32 error 126

electron 调用mysql electron 调用dll方法_python_08

 参考 problem :Error: Dynamic Linking Error: Win32 error 126 ?

输出了路径,发现路径错了

 

3、报错 Error: Dynamic Symbol Retrieval Error: Win32 error 127

electron 调用mysql electron 调用dll方法_electron 调用mysql_09

参考 Got Error “Dynamic Symbol Retrieval Error: Win32 error 127” when load DlL from nodejs

生成的c++ dll有问题,没有导出,所以调用dll的时候找不到对应的方法

 

4、报错 Error: Dynamic Linking Error: Win32 error 193

electron 调用mysql electron 调用dll方法_API_10

参考 记录 electron-vue 通过node ffi调用dll文件踩的坑

 dll错生成了86位的。改成64位即可

 

c++ dll测试代码

testDll.h

// 下列 ifdef 块是创建使从 DLL 导出更简单的
// 宏的标准方法。此 DLL 中的所有文件都是用命令行上定义的 TESTDLL_EXPORTS
// 符号编译的。在使用此 DLL 的
// 任何项目上不应定义此符号。这样,源文件中包含此文件的任何其他项目都会将
// TESTDLL_API 函数视为是从 DLL 导入的,而此 DLL 则将用此宏定义的
// 符号视为是被导出的。
//#ifdef TESTDLL_EXPORTS
//#define TESTDLL_API __declspec(dllexport)
//#else
//#define TESTDLL_API __declspec(dllimport)
//#endif

#define TESTDLL_API __declspec(dllexport)

// 此类是从 dll 导出的
class TESTDLL_API CtestDll {
public:
	CtestDll(void);
	// TODO: 在此处添加方法。
};

extern "C"
{
	TESTDLL_API int ntestDll;
	TESTDLL_API int fntestDll(void);
	TESTDLL_API double Add(double a, double b);
	TESTDLL_API int foo(int value);
}

testDll.cpp

// testDll.cpp : 定义 DLL 的导出函数。
//

#include "testDll.h"

// 这是导出函数的一个示例。
TESTDLL_API int fntestDll(void)
{
    return 0;
}

TESTDLL_API double Add(double a, double b) {
	return a + b;
}

// 这是已导出类的构造函数。
CtestDll::CtestDll()
{
    return;
}


TESTDLL_API int foo(int value)
{
	return value;
}

electron里js的测试代码

var ffi = require('ffi');
var path = require('path');

var dllPath = path.resolve('testdll\\TESTDLL');
console.log("--------------------------------------: " + dllPath);

const lib = ffi.Library(dllPath, {
    'foo': [
        'int', ['int'],
    ],
    'Add': ['double', ['double', 'double'], ],
});

var result = lib.Add('1.0', '2.0');
console.log(result);
var result = lib.foo('1111');
console.log(result);

成功

electron 调用mysql electron 调用dll方法_API_11

参考 electron教程(三): 使用ffi-napi引入C++的dll

生成的c++ dll因为没用extern "C"的方式导出,一直报错,找不到方法。