node.js + Electron 调用 Windows API 踩坑日记

前排提示:深坑,建议使用 C#、C++、VB 等方式 + 本地网络传输或进程管道通信替代。

TOOLS 工具

  • Node.js(12.18.1)
  • Electron(此处使用 ^2.0.0,因为 cef 版本越新,打出来的包越大)
  • webpack(4.44.2)
  • node-ffi(^2.3.0)
  • Python(2.7,你说气不气,还在用老东西)
  • vs_BuildTools(2017(v15)。你到微软官网只能下载 2019(v16),而且无论版本号它文件名都是一样的,你说气不气)

STEPS 开始踩坑!

1. node-gyp

node-gyp 是一个对原生 C++ 模块进行编译的库,类似于 CMake,configure 命令可提供一个跨平台的生成工具,在 Linux/Unix 平台生成 makefile,在苹果平台生成 xcode,在 Windows 平台生成 MSVC 的工程文件。build 命令可进行编译,编译的结果会是一个 .node 文件,可在 bindings 库中引入,作为 node.js 与原生二进制之间的桥梁。

长久以来 linux 的二进制分发一直是巨坑,npm 为了方便干脆就直接源码分发,用户装的时候再现场编译。

安装方法:npm install node-gyp -g

详细说明参见 node-gyp installation

说明中提到你有两个 options。此处建议使用 windows-build-tools,减少不必要的劳动。

2. windows-build-tools

其实在你安装 node.js 的时候,它就已经询问过你是否要安装 gyp 工具链套装,如果你在这里打了勾,那么 windows-build-tools 或许可以省略?(python 版本对不上,可能会有问题)
node.js + Electron 调用 Windows API 踩坑日记_第1张图片
node.js + Electron 调用 Windows API 踩坑日记_第2张图片

安装方法:npm install windows-build-tools -g

不要使用 yarn,因为 windows-build-tools 会从命令行输出进度信息,而 yarn 会把它隐藏掉

npm 安装完成后自动进入 post-install 启动 windows-build-tools 的安装过程,自动安装 python 2.7 和 vsBuildTools。
node.js + Electron 调用 Windows API 踩坑日记_第3张图片

如果这步安装失败了

我在虚拟机测试,这步是一次性成功的。但如果此前安装过 Visual Studio,版本对不上,那就有可能会有问题,需要进行离线安装。

刚才通过 windows-build-tools 下载的文件会存放在 C:/Users/*/.windows-build-tools 里。此处应有 vs_BuildTools.exe,请注意版本需要的是 Visual Studio 2017(15)。如果没有,你需要到网上找一个。请注意如果你是去微软官网下载,那么你必定会下载到最新版,而且版本号不同文件名是一样的,都叫 vs_buildtools__1914864904.1592187139.exe,请注意微软这个坑爹的地方。

离线安装指令:npm install --global windows-build-tools --offline-installers="C:/Users/*/.windows-build-tools"

3. node-ffi

ffi 的作用是提供 binding.gyp 给 node-gyp 编译,提供 js 调用 dll 的接口。编译的步骤发生在 post-install,你会发现命令行有中文输出,这是 node-gyp 在调用 Visual Studio 编译的缘故(微软这点倒是做得不错)。

安装指令:npm install ffi

如果这步安装失败了

Windows 恶心的地方在此处,如果是一台干净的电脑,那么这步应该是不会有问题的。但如果此前安装过 Visual Studio,版本对不上,那就有可能会有问题。你可能会遇到这种问题:MSB4019: 未找到导入的项目:Microsoft Visual Studio\2019\Community\Common7\IDE\VC\VCTargets\Microsoft.Cpp.Default.props。出现这种情况,说明 Visual Studio Build Tools 安装有问题,需要重新安装。

回到前一步,找到 vs_BuildTools.exe(版本 15),双击打开。
node.js + Electron 调用 Windows API 踩坑日记_第4张图片
勾选“Visual C++ 生成工具”,在右侧面板至少勾选“Windows SDK”(建议保持默认,我也不知道另外两个是干嘛的),然后安装。安装完成后重新执行 npm install ffi

4. electron-rebuild

node-gyp 编译出来的 .node 不适用于 electron 环境,因此你需要 npm install --save-dev electron-rebuild,然后 .\node_modules\.bin\electron-rebuild

5. 开始愉快的~~(我相信你已经困了)~~ 开发

const ffi = require('ffi')
const kernel32 = ffi.Library('kernel32', {
     
	'Beep': ['int', ['int', 'int']]
})
kernel32.Beep(1000, 1000)

如果你听到了“哔”的一声,那你已经成功啦!

TROUBLESHOOTING 疑难解答

  • 安装前记得打开系统还原,如果把 Visual Studio Installer 搞崩了那就删掉文件夹再装。

  • 默认情况下 windows-build-tools 会设置 msvs 和 python 的环境变量。如果有问题,执行 npm config set msvs_version 2017,python 方面有问题就执行 npm config set python python2.7(记得把 python 2.7 也加到 PATH 里),还有人说执行 set VCTargetsPath=C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\v140(对应 VS 2015),我没试过

  • Cannot read property 'indexOf' of undefined:追查源码,找到 binding.js,错误发生在 Error.prepareStackTrace 的 CallSite 没有 getFileName 方法,解决方案是修改 binding.js 源码,for 外面 var st_arr = new Error().stack.match(/\([^\)]+\)/g).map(str=>str.slice(1,str.indexOf(':',str.indexOf(':')+1))),for 里面 fileName = st_arr[i];

  • Could not locate the bindings file:编译后的 bindings.node 放在了 /node_modules/ref/build 下,把它复制到 /build 下即可解决

  • Requiring Native Modules in the Renderer Process to be NAPI or Context Aware #18397:使用较低的 electron 版本,详见 issues Timeline

  • A dynamic link library (DLL) initialization routine failed:Electron 需要再编译一遍 npm install --save-dev electron-rebuild,详见 https://www.cnblogs.com/juwan/p/12255659.html。如果需要生成特定 architecture 的 .node 如 ia32,则 .\node_modules.bin\electron-rebuild --arch ia32

  • Path must be a string. Received undefined:binding.js 1.0 版本有问题,需要更新到 1.4 版本,在 getFileName() 里解决了 Electron 路径的问题,因此进入到 node_modules/ffi,devDependences 需要手动加入 binding.js,然后再手动修改上述 error trace 方法

  • The specified module could not be found:把各种 .node 文件都放到提示里的文件夹去,比如 /build,/dist/build。记得降低 Electron 版本!!!

REFERENCES 参考链接

node.js 上构建 Windows 环境指引
node-gyp
windows-build-tools
node-ffi
滔滔清风科技馆

BACKGROUND 入坑原由

受到同学委托做一个开机密码的软件。事实上按照以往的做法,使用 VB 最为方便,但总感觉糊弄了点,加上现在主做前端开发方向,想尝试使用 electron 完成这个功能,所以入了这坑。虽然成果不佳,但至少体验到了用跨平台框架做 Windows 本地化开发有多坑……


2020-12

你可能感兴趣的:(node.js,windows,dll)