|
|
本帖最后由 cutebe 于 2026-3-30 20:50 编辑
使用方法: //JS代码,在WPS的JSA宏中使用 //适用于还没有ffi的老版本WPS
- var 剪贴板文本=获取剪贴板文本();
- var 修改文本="新文本:\n"+ 剪贴板文本 +"\n字符串结束!";
- 设置剪贴板文本(修改文本); //新文本放入剪贴板,可粘贴使用
复制代码
办公软件WPS的JSA宏无法直接使用系统剪贴板,但可以通过ExecuteExcel4Macro的CALL来调用系统功能以实现剪贴板操作。
最新版本的WPS可以用FFI/ffi方便实现,但没有这些的中间版本就需要ExecuteExcel4Macro了。
使用ExecuteExcel4Macro调用CALL时有所限制。CALL的函数其 参数/返回值 如果是字符串,则最大只到255字节(缓冲区256字节,包含有一字节结束符)。所以只要调用的函数(系统API)有其中一个参数是字符串,或是返回值是字符串,都需要切成小段逐段处理。
设置剪贴板文本("文本/字符串");
- function 设置剪贴板文本(文本内容){ //参数为字符串
- let 执行宏调用=ExecuteExcel4Macro; //调用系统应用接口。简化书写
- let 分段文本=[],段长度=127,分段字节=[],总字节=0; //去掉结束符\0,双字节文字最长127
- for(let 起始=i=0;起始<文本内容.length;起始+=段长度,i++){
- 分段文本.push(文本内容.slice(起始,起始+段长度));
- 分段字节.push(分段文本[i].replace(/[^\x00-\xff]/g,'xx').length); //计算字节数
- 总字节+=分段字节[i];
- } //console.clear(); //清空立即窗口(控制台)信息
- if (执行宏调用(`CALL("User32","OpenClipboard","AJ",0)`)){ //打开剪贴板
- if(执行宏调用(`CALL("user32.dll","EmptyClipboard","A")`)){ //清空剪切板
- const 内存句柄=执行宏调用(`CALL("Kernel32","LocalAlloc","JJJ",${0x42},${总字节+1})`); //分配内存
- //console.log("内存块大小:"+执行宏调用(`CALL("Kernel32","LocalSize","JJ",${内存句柄})`));
- if(内存句柄){ //内存分配成功。然后锁、写、解内存。最后设置剪贴板。
- const 内存地址=执行宏调用(`CALL("kernel32.dll","LocalLock","JJ",${内存句柄})`); //锁定对象,返回地址
- for(let 偏移字节=i=0;i<分段文本.length;i++){ //字符串(JS变量)分批复制到内存中。分批是因为有限长
- 执行宏调用(`CALL("Kernel32","lstrcpynW","JJFJ",${内存地址+偏移字节},"${分段文本[i].replace(/"/g,'""')}",${分段字节[i]})`);
- 偏移字节+=分段字节[i]; //返回地址J。
- }
- 执行宏调用(`CALL("kernel32.dll","LocalUnlock","JJ",${内存句柄})`); //解锁内存对象
- let 剪贴板文本=执行宏调用(`CALL("User32","SetClipboardData","JJJ",1,${内存句柄})`);
- 执行宏调用(`CALL("Kernel32","LocalFree","JJ",${内存句柄})`); //释放内存
- }else{console.log("未能分配内存!");} //数据放入剪切板,参数为1(CF_TEXT)则返回文本
- }else{console.log('未能清空剪贴板!');}
- 执行宏调用(`CALL("User32.dll","CloseClipboard","A")`); //关闭剪贴板,以释放控制权。
- }else{alert('无法打开剪贴板!');}
- }
复制代码
var 字符串=获取剪贴板文本();
- function 获取剪贴板文本(){ //返回字符串
- let 内存地址,剪贴板文本="",执行宏调用=ExecuteExcel4Macro;
- if(执行宏调用(`CALL("user32.dll","OpenClipboard","JJ",0)`)){ //打开剪贴板
- const 内存句柄=执行宏调用(`CALL("user32","GetClipboardData","JJ",1)`); //获取剪贴板文本,返回句柄。
- if(内存句柄){ //锁定内存对象,获取内存地址
- 内存地址=执行宏调用(`CALL("kernel32","LocalLock","JJ",${内存句柄})`);
- let 总字节,偏移字节=0,段长度=127,分段文本='';
- 总字节=执行宏调用(`CALL("Kernel32","lstrlenA","JJ",${内存地址})`); //剪贴板文本字节数
- while(偏移字节<总字节){ //返回字符串F。返回值超255字节时,也需要分段操作
- 分段文本=执行宏调用(`CALL("Kernel32","lstrcpynW","FFJJ","",${内存地址+偏移字节},${段长度})`);
- 偏移字节+=分段文本.replace(/[^\x00-\xff]/g,'xx').length; //计算分段文本字节数
- 剪贴板文本+=分段文本;
- }
- 执行宏调用(`CALL("kernel32.dll","LocalUnlock","JJ",${内存句柄})`); //解锁
- }else{console.log("未能获取剪贴板数据的内存句柄!");}
- 执行宏调用(`CALL("User32","CloseClipboard","J")`); //关闭剪贴板,让其它应用可以使用剪贴板
- return 剪贴板文本; //返回字符串
- }else{alert('无法打开剪贴板!');}
- }
复制代码
//在WPS中使用ExecuteExcel4Macro宏调用CALL,限制字符串类型的参数限长255字节。
//一个汉字占2个字节 //参数为字符串时需要引号包起,且类型必须用F。
let 文本字节长度=执行宏调用(`CALL("kernel32","lstrlenA","JF","${文本内容}")`);
//使可以处理双引号"而不提示错误
执行宏调用(`CALL("Kernel32","lstrcpynW","JJFJ",${内存地址},"${字符串.replace(/"/g,'""')}",${字长度})`);
let 文本字节长度=执行宏调用(`CALL("kernel32","lstrlenA","JF","${文本内容.replace(/["]/g,'x')}")`);
let 文本字节长度=执行宏调用(`CALL("kernel32","lstrlenA","JF","${文本内容.replace(/\"/g,'y')}")`);
let 文本字节长度=执行宏调用(`CALL("kernel32","lstrlenA","JF","${文本内容.replace(/"/g,'z')}")`);
//参数为(字符串所在的)内存地址时不限制
let 文本字节长度=执行宏调用(`CALL("Kernel32","lstrlenA","JJ",${内存地址})`); |
|