使用ffi-napi+ref-napi 调用dll
ffi-napi 是一个用于 js 加载和调用动态库的 node.js 插件。
ref-napi 提供了 c++ 的一些类型,可以将 buffer 实例转化成“指针”。
前期准备
下载 windows-build-tools,需要用管理员模式运行,
npm install –global –production windows-build-tools -vs2015
这个会自动下载 python2.7 和 c++ 的编译插件。
安装
npm install ffi-napi
npm install ref-napi
安装时可能遇到的坑
提示 node-gyp rebuild 的报错,这种情况一般是 node-gyp 的版本问题,安装最新版本覆盖一下就可以,执行 npm install node-gyp ,然后在 package.json 删掉这个依赖。
使用
1、创建dll
使用vs2019 创建
2、实现文件复制功能
头部引用:
#include<windows.h>
#include<shellapi.h>
#include<atlstr.h>
#include<shlobj.h>
void unicodeToUtf8(wchar_t* unicode,CString& re){
int len;
len = WideCharToMultiByte(CP_UTF8,0,unicode,-1,NULL,0,NULL,NULL);
char* szUtf8 = (char*)malloc(len + 1);
memset(szUtf8, 0, len + 1);
WideCharToMultiByte(CP_UTF8, 0, unicode, -1, szUtf8, len, NULL, NULL);
CString temp(szUtf8);
re = temp;
free(szUtf8);
szUtf8 = NULL;
}
void GetFileFromClipboard(char* path){
UINT uDropEffect = RegisterClipboardFormat(_T("Preferred DropEffect"));
UINT cFiles = 0;
if (OpenClipboard(NULL))
{
HDROP hDrop = HDROP(GetClipboardData(CF_HDROP/*CF_UNICODETEXT*/));
if (hDrop)
{
cFiles = DragQueryFile(hDrop, (UINT)-1, NULL, 0);
TCHAR szFile[MAX_PATH];
CString str = "";
for (UINT count = 0; count < cFiles; count++)
{
DragQueryFile(hDrop, count, szFile, sizeof(szFile));
CString tmp(szFile);
if (count + 1 != cFiles) {
str = str + tmp + L"|";
}
else {
str = str + tmp;
}
}
CString re="";
unicodeToUtf8(str.AllocSysString(), re);
strcpy_s(path, strlen(re) + 1,re);
}
}
CloseClipboard();
}
3、生成dll的注意事项
要注意打包的位数,不然在调用时会报错。
js 使用 ffi 引用:
const dllPath = "copy.dll";
let buffer:any= ref.allocCString('');
const library = ffi.Library(dllPath, {
GetFileFromClipboard: ["void", [ref.types.CString]],
});
library.GetFileFromClipboard(buffer);
const re = ref.readCString(buffer, 0);
buffer = null;
console.log(re)
使用字符串传参的一些坑
在之前,我返回复制的内容都是通过 return 返回的。在后来测试时,发现有一定几率返回的是乱码。
一开始以为是编码问题,找了各种转码、代码都不行,后面想到在c++ 中字符串是存指针的,返回可能已经被释放掉了,所以要使用从外面申请内存存进去。
其他坑
之前试过使用其他语言写 dll,比如 golang,对于非指针操作还算正常,但是有指针操作情况下会报错,估计是非标准的问题。
总结
总的来说,electron 调用 dll 还是比较简单的,难点在于编写 dll 上,毕竟作为前端人员大多数情况下使用的是 js ,c++ 基本很少用到。而 electron 作为前端写桌面的玩具,能用 js 实现就尽量使用 js ,不建议再用其他方式。
给大家分享更多 electron 实战中的点滴,如果大家对此感兴趣,欢迎各位关注、留言,大家的支持就是我的动力!