一、背景
在使用electron开发桌面应用,尤其是类似微信的即时通讯IM应用,会考虑各种情况的文件操作,比如弹窗选择、拖拽、或者复制粘贴的方式发送文件消息,这些操作都是基于文件本身的,所以都好处理。但是如果对文件消息进行复制,就会存在两种可能性:
- 一是本文件消息对应的服务器文件存在时,只需要发送一个同样的文件消息(文件直接指向原消息的服务器文件)即可;
- 再一个就是原文件消息对应的服务器文件不存在时,又有两种情况需要考虑:
2.1 如果本地文件也不存在时,当然复制、转发之类的也就不能再显示了;
2.2 如果本地文件存在时(如下图所示)
在复制时就需要用消息体中的文件路径,将本地文件写入到剪贴板中,也就是本文所讲内容的使用场景;
二、使用
- clone工程【https://gitee.com/lykiao/copy-file-to-clipboard.git】,使用vs2019编译工程生成【CopyFileToClipboard.dll】
- electron工程的src文件夹(background.js的同级目录)中,创建【CopyFileToClipboard.js】,
并引入本工程编译生成的dll文件【CopyFileToClipboard.dll】,也可使用【dll_x64_release】文件夹中提供的现成dll文件
【CopyFileToClipboard.js】的全代码如下:
// 不能用import,会报错,必须放在最外层引入
const { app } = require('electron');
try{
const ffi = require('ffi-napi');
var path = require('path');
// 重启系统im自动启动时路径有变,需要重置绝对路径,否则报Win32 error 126错误(此处貌似不需要)
// var oldPath = process.env.PATH;
// var dllPath = 'C:\\Windows\\SysWOW64\\';
// process.env['PATH'] = `${process.env.PATH};${dllPath}`;
const kernel32_ffi = ffi.Library('kernel32', {
SetDllDirectoryA: ['bool', ['string']]
});
// process.env['PATH'] = oldPath;
// 重启系统im自动启动时路径有变,需要指定绝对路径,否则报Win32 error 126错误
var resourcesPath = getResourcesPath();
kernel32_ffi.SetDllDirectoryA(resourcesPath); // 必须指定绝对路径
// c++的dll中不能带namespace和class,否则找不到function
const CopyFileToClipboard = ffi.Library('CopyFileToClipboard.dll', {
'RunCopyFile': // 声明这个dll中的一个函数
[
'int', ['string'], // 前为出力参数,后为入力参数
],
});
const RunCopyFile = function(fullPath){
console.log("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++文件copy开始: " + fullPath);
var result = CopyFileToClipboard.RunCopyFile(fullPath);
console.log("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++文件copy结束: " + result);
};
module.exports = {CopyFileToClipboard, RunCopyFile};
}catch(e){
// 如果background.js中一开始就引入此js,taskbar中点击翼丰信,background.js中second-instance激活主窗体后会报dll错,已在使用时引入,以防万一,在此catch住
console.log("=======error: ffi-napi 引入 CopyFileToClipboard.dll 出错!!!")
console.error(e);
}
// 此方法必须放在外层,而且不能写成const getResourcesPath = function(){}的形式,否则报错
function getResourcesPath(){
if (process.env.WEBPACK_DEV_SERVER_URL){
const devUrl = 'resources/dll/';
return devUrl;
}else{
var appPath = path.dirname(app.getPath('exe'));
const eveUrl = appPath + '\\resources\\dll\\';
console.log("************CopyFileToClipboard prod dllPath: " + eveUrl);
return eveUrl;
}
}
3、在【background.js】中引入以上【CopyFileToClipboard.js】
// 引入:
const { RunCopyFile } = require("./CopyFileToClipboard");
// 使用:
// 执行本地文件copy操作
ipcMain.on('CopyFileToClipboard', (event, args) => {
console.log("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++执行文件copy: " + args.fullPath);
// 之前以下两种情况报错是因为重启电脑im自动启动导致环境变量指定的路径有变,已解决:
// 1、电脑重启后立即启动app,会报ffi-napi找不到dll的win32 error 126错误,导致dll加载失败
// 2、taskbar任务栏右键点选翼丰信后,在触发second-instance前也会报上面的错
// require("./CopyFileToClipboard").RunCopyFile(args.fullPath);
RunCopyFile(args.fullPath);
});
4、前端vue文件可直接发送事件,触发以上后台方法执行
// 发送事件:
ipcRenderer.send('CopyFileToClipboard', {fullPath: message.messageContent.localPath});
// 执行粘贴:
// 这样,在ctrl+v调起的handlePaste(e)方法中就可以从剪贴板中获取到文件了
var clipboardFiles = e.clipboardData.files;
以上,也请多注意代码中的注释,都是个人爬坑时留下的痕迹 TT