找回密码
 注册
搜索
系统gho:最纯净好用系统下载站投放广告、加入VIP会员,请联系 微信:wuyouceo
查看: 89|回复: 4

办公软件WPS的JSA中获取/设置电脑时间

[复制链接]
发表于 昨天 21:03 | 显示全部楼层 |阅读模式
办公软件WPS的表格:通过ExecuteExcel4Macro调用WinAPI实现


函数:
  1. function 获取电脑时间(){        //返回时间数组缓冲
  2.         const 执行宏调用=ExecuteExcel4Macro;
  3.         const 时间结构字节数=16;        //时间结构2*8=16字节                //申请内存
  4.         const 内存地址=执行宏调用(`CALL("Kernel32","VirtualAlloc","JJJJJ",0,${时间结构字节数},${0x3000},4)`);
  5.         执行宏调用(`CALL("Kernel32","GetLocalTime","JJ",${内存地址})`);        //获取电脑时间数据
  6.         let 时间数组缓冲=内存读取数据(内存地址,时间结构字节数);        /*****读取内存数据*****/
  7.         执行宏调用(`CALL("Kernel32", "VirtualFree", "JJJJ", ${内存地址}, 0, ${0x8000})`);        //释放内存
  8.         return 时间数组缓冲;
  9. }
  10. function 设置电脑时间(时间数组缓冲){
  11.         const 执行宏调用=ExecuteExcel4Macro;
  12.         const 时间结构字节数=16;                //申请内存
  13.         const 内存地址=执行宏调用(`CALL("Kernel32","VirtualAlloc","JJJJJ",0,${时间结构字节数},${0x3000},4)`);
  14.         数据写入内存(内存地址,时间数组缓冲,时间结构字节数);        //写入时间结构
  15.         let 设置时间=执行宏调用(`CALL("Kernel32","SetLocalTime","AJ",${内存地址})`);        //设置时间
  16.         if(!设置时间){console.log("时间设置失败!");}
  17.         执行宏调用(`CALL("Kernel32", "VirtualFree", "JJJJ", ${内存地址}, 0, ${0x8000})`);        //释放内存
  18. }
复制代码


测试与调用的函数:
  1. function 获取设置本机时间测试(){
  2.         let 时间数组缓冲=获取电脑时间();        /*****获取时间*****/
  3.         console.clear();显示数组缓冲(时间数组缓冲);        /*****显示时间数据*****/
  4.        
  5.         const 数据操作=new DataView(时间数组缓冲);        //将日期时间数据转成常用文本形式
  6.         let 年=数据操作.getInt16(0,true),月=数据操作.getInt16(2,true);
  7.         let 星期=数据操作.getInt16(4,true),日=数据操作.getInt16(6,true);
  8.         let 时=数据操作.getInt16(8,true),分=数据操作.getInt16(10,true);
  9.         let 秒=数据操作.getInt16(12,true),毫秒=数据操作.getInt16(14,true);
  10.         console.log(年+"-"+月+"-"+日+" 周"+星期+" "+时+':'+分+':'+秒+'.'+毫秒);        //显示日期时间文本
  11.        
  12.         //分钟减15
  13.         分=(分+60-15)%60;数据操作.setInt16(10,分,true);
  14.         设置电脑时间(时间数组缓冲);        /*****设置时间*****/
  15. }
  16. function 内存读取数据(内存地址,字节数){        //返回数组缓冲
  17.         const 执行宏调用=ExecuteExcel4Macro;
  18.         let 偏移,i,读取字节=[],读出数据;
  19.         for(偏移=i=0;偏移<字节数;i++){
  20.                 if(字节数-偏移>=4){读取字节[i]=4;偏移+=4;}
  21.                 else{if(字节数-偏移>=2){读取字节[i]=2;偏移+=2;}
  22.                 else{if(字节数-偏移==1){读取字节[i]=1;偏移++;}}}
  23.         }
  24.         const 数组缓冲=new ArrayBuffer(字节数);        //用于存储读出的数据
  25.         const 数据操作=new DataView(数组缓冲);
  26.         for(偏移=i=0;偏移<字节数;i++){        //库Kernel32.dll和NtDll.dll里都有RtlMoveMemory        //读出
  27.                 读出数据=执行宏调用(`CALL("Kernel32","RtlMoveMemory","1NJJ",${内存地址},${内存地址+偏移},${读取字节[i]})`);
  28.                 if(读取字节[i]==4){数据操作.setInt32(偏移,读出数据,true);偏移+=4;}
  29.                 else{if(读取字节[i]==2){数据操作.setInt16(偏移,读出数据,true);偏移+=2;}
  30.                 else{if(读取字节[i]==1){数据操作.setInt8(偏移,读出数据,true);偏移++;}}}
  31.         }
  32.         return 数组缓冲;        //返回
  33. }

  34. function 数据写入内存(内存地址,数组缓冲,字节数){
  35.         const 数据操作=new DataView(数组缓冲);
  36.         let 偏移=i=0,待写数据=[],写入字节=[];
  37.         while(字节数>偏移){
  38.                 if(字节数-偏移>=4){待写数据[i]=数据操作.getInt32(偏移,true);写入字节[i]=4;i++;偏移+=4;}
  39.                 else{if(字节数-偏移>=2){待写数据[i]=数据操作.getInt16(偏移,true);写入字节[i]=2;i++;偏移+=2;}
  40.                 else{if(字节数-偏移==1){待写数据[i]=数据操作.getInt8(偏移,true);写入字节[i]=1;i++;偏移++;}}}
  41.         }
  42.         const 执行宏调用=ExecuteExcel4Macro;
  43.         for(偏移=i=0;i<写入字节.length;i++){        //写入
  44.                 执行宏调用(`CALL("Kernel32","RtlMoveMemory","2JNJ",${内存地址+偏移},${待写数据[i]},${写入字节[i]})`);
  45.                 偏移+=写入字节[i];
  46.         }
  47. }
  48. function 显示数组缓冲(数组缓冲){
  49.         const 数据操作=new DataView(数组缓冲);
  50.         var 字节数码串=[],字符串=[],行号,四分隔,八分隔;
  51.         for(let 偏移=0;偏移<数组缓冲.byteLength;偏移++){
  52.                 var 字节数码=数据操作.getInt8(偏移);
  53.                 行号=Math.floor(偏移/16);
  54.                 if((偏移+1)%4){四分隔=''}else{四分隔=' '};
  55.                 if((偏移+1)%8){八分隔=''}else{八分隔=' '};
  56.                 if(typeof 字节数码串[行号]=="undefined"){字节数码串[行号]=''}
  57.                 var 字节高位=(字节数码>>>4&0xF).toString(16).toUpperCase(),字节低位=(字节数码&0xF).toString(16).toUpperCase();
  58.                 字节数码串[行号]+=字节高位+字节低位+" "+四分隔+八分隔;
  59.                 if(typeof 字符串[行号]=="undefined"){字符串[行号]=''}
  60.                 if(字节数码){字符串[行号]+=String.fromCharCode(字节数码);}else{字符串[行号]+=' ';}
  61.         }
  62.         for(let 行号=0;行号<字节数码串.length;行号++){
  63.                 var 十六进制行号=('000'+(行号<<4).toString(16)).slice(-4).toUpperCase();
  64.                 console.log(十六进制行号+":"+字节数码串[行号]+"\t["+字符串[行号]+"]");
  65.         }
  66. }
复制代码


 楼主| 发表于 昨天 21:10 | 显示全部楼层
时间调乱了,校时恢复时间:        //批处理脚本,用到三方命令wget.exe
  1. ::校时百度搜索北京时间.bat
  2. ::网站:百度搜索“北京时间”        //页面:http://www.baidu.com/s?wd=北京时间
  3. ::用wget尝试下载页面,返回信息中提取UTC秒数,w32tm转换成北京时间,最后设置时间。
  4. ::百度上获取的为 1970-1-1 0h 到当前时间的 s 秒数
  5. ::w32tm 使用的是 1601-1-1 0h 到当前时间的 (10^-7)s (即 0.1 微秒 / 100 纳秒)数。
  6. ::从 1601-1-1 0h 到 1970-1-1 0h 的时间差为 11644473600 s。
  7. @echo off
  8. cd/d %~dp0
  9. echo 校时前:
  10. echo %date% %time%

  11. ::提取UTC秒数s(Wget.exe检查https证书时错误并返回),转换为w32tm.exe可用格式
  12. for /f "tokens=*" %%s in ('"wget "http://www.baidu.com/s?wd=北京时间" 2>&1|findstr "timestamp""') do (
  13.         set "TS=%%s"
  14. )
  15. set "T1%TS:*timestamp=%000"        ::加三个0变毫秒
  16. echo\&echo 时间戳:%T1% 毫秒
  17. title 校时 本机时间校正为北京时间

  18. ::例UTC=1767832716000 ms
  19. set T2=11644473600000
  20. set/a _T=1%T1:~-9%-1000000000+%T2:~-9%
  21. set _T_=%_T:~,-9%&set _T=%_T:~-9%
  22. set/a T_=%T1:~,-9%+%T2:~,-9%+_T_
  23. echo /ntte:%T_%%_T%0000

  24. ::设置日期时间(增加四个0变每100纳秒)        //1970-01-01 周四 8:00:00
  25. ::(for /f "tokens=4,5" %%d in ('w32tm /ntte %T_%%_T%0000') do (date %%d&time %%e)) 2>nul
  26. for /f "tokens=4-6" %%d in ('w32tm /ntte %T_%%_T%0000') do (date %%d&time %%e)

  27. echo+
  28. echo 校时后:
  29. echo %date% %time%
  30. ping -n 3 127.1>nul
  31. goto :eof
复制代码
回复

使用道具 举报

发表于 昨天 22:07 | 显示全部楼层
不明觉厉,惭愧
回复

使用道具 举报

发表于 昨天 22:28 | 显示全部楼层
过于繁琐
回复

使用道具 举报

 楼主| 发表于 昨天 22:59 | 显示全部楼层
主要是验证了JSA中调用WinAPI时 输出型结构参数 可获取,输入型结构参数 也可通过内存引用。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

小黑屋|手机版|Archiver|捐助支持|无忧启动 ( 闽ICP备05002490号-1|闽公网安备35020302032614号 )

GMT+8, 2026-4-22 03:52

Powered by Discuz! X5.0

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表