Electron的剪贴板不够用?给你准备了个更好的

2,924 阅读3分钟

遇到问题

在使用Electron开发IM应用时,难免会遇到拷贝多文件并发送的需求,那么要怎样去实现呢?

打开Electron的文档[剪贴板 | Electron (electronjs.org)](https://www.electronjs.org/docs/api/clipboard),看一看吧!

文档中提供了 readTextwriteTextreadImagewriteImage ...... 等等方法。呃,不过好像没有解决这个需求。😵

那要怎么办呢? 这时候就要就要找出昔日的朋友陈佳佳(C++)了

拿到剪帖板中文件的路径

打开/关闭 剪贴板

剪切板相关操作文档: 剪贴板函数 - Win32 apps | Microsoft Docs

BOOL OpenClipboard( HWND hWndNewOwner ); // 打开剪贴板
HANDLE GetClipboardData( UINT uFormat ); // 获取数据句柄
BOOL CloseClipboard();  // 关闭剪贴板
获取剪贴板中文件数量

shellapi.h文档: DragQueryFileA function (shellapi.h) - Win32 apps | Microsoft Docs

UINT DragQueryFileA( 
    HDROP hDrop,
    UINT iFile,
    LPSTR lpszFile,
    UINT cch
);

iFile 字段的说明如下

Index of the file to query. If the value of this parameter is 0xFFFFFFFF, DragQueryFile returns a count of the files dropped.

也就是说 iFile 的值设置为 0xFFFFFFFF 即可返回文件的数量

连同将数据句柄一起传入即可拿到文件的数量,如下代码

HDROP hDrop = (HDROP)::GetClipboardData(CF_HDROP);  // 获取数据句柄

if (hDrop) {
    UINT fileCount = ::DragQueryFile(hDrop, 0xFFFFFFFF, NULL, 0); // 获取剪贴板中文件数量
    
    cout<<'The File in clipboard Number is: '<<fileCount<<endl;
}
获取剪贴板文件路径

iFile 字段的说明的后半句如下

If the value of this parameter is between zero and the total number of files dropped, DragQueryFile copies the file name with the corresponding value to the buffer pointed to by the lpszFile parameter.

也就是说 iFile 的值如果为 0 - fileCount 之间的话,返回的是被拷贝的文件的名称。 即得到如下代码:


char filePath[MAX_PATH + 1] = { 0 }; // 文件路径数组
for (UINT i = 0; i < fileCount; i++)
{
        memset(filePath, 0, MAX_PATH + 1); // 清空数组
        DragQueryFile(hDrop, i, filePath, MAX_PATH); // 往数组写入文件名

        cout<<filePath<<endl;
}

注: MAX_PATH 为最长路径名的宏定义,定义如下 #define MAX_PATH 260

至此基本功能都实现了,代码如下,我们跑一下吧

image.png

运行结果准确

image.png

拿到文件路径后就可以交给NodeJSfs模块操作了

生成 .node 文件

我们参考better-sqlite3的源码将该项目命名为better-clipboard,并编译生成 better_clipboard.node。 项目路径为 simo-an/better-clipboard: A better clipboard for Electron (NodeJS). (github.com)

注: 生成过程参考 C++ 插件 | Node.js API 文档 (nodejs.cn)

安装构建better-clipboard

在你的Electron项目中安装并重新构建better_clipboard.node

npm i better-clipboard

electron-rebuild -f -w better-clipboard

如果你使用Webpack,请添加如下代码 Help me use Electron! · Issue #126 · JoshuaWise/better-sqlite3 (github.com)

config.externals = {
  'better-clipboard': 'commonjs better-clipboard'
}

注: 遇到构建的问题可参考better-sqlite3中的解决方案,或者给我提issue

使用 better-clipboard

我在 better_clipboard.node 的基础上再次做了拓展,可以直接拿到剪贴板中的File或者Buffer 代码参考: better-clipboard/better-clipboard.ts at master · simo-an/better-clipboard (github.com)

使用方法

import { betterClipboard } from 'better-clipboard';

betterClipboard.readFilePathList(); // get the path of file which in clipboard
betterClipboard.readBufferList();
betterClipboard.readFileList();


betterClipboard.writeFileList([]); // write file into clipboard via file path

看一下我这边在 ng-electron 中的测试结果吧

image.png

分别使用Electron自带的剪贴板和better-clipboard来做个比较

image.png

可见better-clipboard出色的完成了任务。😁

更详细的代码,构建过程欢迎访问 better-clipboard: A better clipboard for Electron (NodeJS),同样欢迎starfork。😁