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

办公软件WPS的JSA中列举窗口信息

[复制链接]
发表于 昨天 22:06 | 显示全部楼层 |阅读模式
办公软件WPS的表格:通过ExecuteExcel4Macro调用WinAPI实现
       //鼠标指向窗口,先向上找到父祖窗口,再从顶层的根窗口列举所有子孙窗口。可用于窗口内部关系查询

主要用到的接口函数:GetParent、FindWindowExA


函数及测试:
  1. function 寻根开枝叶测试(){        //找到根再顺枝到叶
  2.         let 窗口句柄=鼠标所指窗口句柄();
  3.         console.clear();
  4.         while(窗口句柄){        //收藏
  5.                 var 句柄=窗口句柄;
  6.                 let 窗口信息=获取窗口信息(窗口句柄);
  7.                 窗口信息显示(窗口信息,"","窗口");
  8.                 窗口句柄=父窗口(窗口句柄);
  9.         }
  10.         const 根句柄=句柄,根序=1;
  11.         console.log("\t["+根序+"]根句柄:"+根句柄);
  12.         //生长
  13.         let 枝句柄=根句柄;
  14.         子弟窗口(枝句柄,0,根序,0);
  15. }
  16. function 父窗口(窗口句柄){        //返回父窗口句柄
  17.         const 执行宏调用=ExecuteExcel4Macro;
  18.         父句柄=执行宏调用(`CALL("User32","GetParent","JJ",${窗口句柄})`);
  19.         return 父句柄;
  20. }
  21. function 子弟窗口(父句柄,兄句柄,父祖序,兄弟序){        //显示窗口信息树
  22.         let 子句柄=下个子窗口(父句柄,兄句柄);
  23.         while(子句柄){
  24.                 兄弟序++;let 传承=父祖序+'.'+兄弟序;
  25.                 let 子窗口信息=获取窗口信息(子句柄);
  26.                 窗口信息显示(子窗口信息,"["+传承+"]","");
  27.                 子弟窗口(子句柄,0,传承,0);        //---回溯---//
  28.                 子句柄=下个子窗口(父句柄,子句柄);
  29.         }
  30. }
  31. function 下个子窗口(父句柄,兄句柄){return 下一个子窗口(父句柄,兄句柄,0,0);}
  32. function 下一个子窗口(父句柄,上个子句柄,标题,类){
  33.         const 执行宏调用=ExecuteExcel4Macro;
  34.         var 子句柄;
  35.         if(!标题){        //标题为0               
  36.                 if(!类){        //类为0
  37.                         子句柄=执行宏调用(`CALL("User32","FindWindowExA","JJJJJ",${父句柄},${上个子句柄},0,0)`);
  38.                 }else{
  39.                         子句柄=执行宏调用(`CALL("User32","FindWindowExA","JJJFJ",${父句柄},${上个子句柄},"${类}",0)`);
  40.                 }
  41.         }else{
  42.                 if(!类){        //类为0
  43.                         子句柄=执行宏调用(`CALL("User32","FindWindowExA","JJJJF",${父句柄},${上个子句柄},0,"${标题}")`);
  44.                 }else{
  45.                         子句柄=执行宏调用(`CALL("User32","FindWindowExA","JJJFF",${父句柄},${上个子句柄},"${类}","${标题}")`);
  46.                 }
  47.         }
  48.         return 子句柄;
  49. }
  50. function 鼠标所指窗口句柄(){        //返回窗口句柄
  51.         const 执行宏调用=ExecuteExcel4Macro;
  52.         let 鼠标指针坐标=获取鼠标位置();        //===调用函数===/
  53.         let 水平=鼠标指针坐标[0],垂直=鼠标指针坐标[1];        //鼠标指针处窗口句柄        //扩展了一个参数
  54.         let 窗口句柄=执行宏调用(`CALL("User32", "WindowFromPoint", "JJJ", ${水平},${垂直})`);
  55.         return 窗口句柄;
  56. }
  57. function 获取鼠标位置(){        //返回坐标数组[x,y]
  58.         const 执行宏调用=ExecuteExcel4Macro;
  59.         var 坐标结构=执行宏调用(`CALL("User32","GetCursorPos","1E",0)`);        //参数:4+4字节坐标结构
  60.         const 缓冲区=new ArrayBuffer(8); //8字节对应64位
  61.         const 数据操作=new DataView(缓冲区);        //操作对象
  62.         数据操作.setFloat64(0,坐标结构);        //(操作)写入64位数
  63.         let 坐标=[];
  64.         坐标[0]=数据操作.getInt32(4);        //取32位坐标x
  65.         坐标[1]=数据操作.getInt32(0);        //取32位坐标y
  66.         return 坐标;
  67. }
  68. function 获取窗口信息(窗口句柄){        //返回数组[句柄,标题,类,坐标]
  69.         let 窗口标题=获取窗口标题(窗口句柄);
  70.         let 窗口类名=获取窗口类名(窗口句柄);
  71.         let 窗口坐标=获取窗口坐标(窗口句柄);
  72.         return [窗口句柄,窗口标题,窗口类名,窗口坐标];
  73. }
  74. function 窗口信息显示(窗口信息,目录,说明){        //句柄、标题、类、坐标
  75.         let 窗口句柄=窗口信息[0],窗口标题=窗口信息[1];
  76.         let 窗口类名=窗口信息[2],窗口坐标=窗口信息[3];
  77.         console.log(目录+说明+"句柄:"+窗口句柄+"\t"+说明+"标题:"+窗口标题+"\t"+说明+"类名:"+窗口类名+"\t"+说明+"坐标:"+窗口坐标);
  78. }
  79. function 获取窗口标题(窗口句柄){
  80.         const 执行宏调用=ExecuteExcel4Macro;
  81.         let 窗口标题长度=执行宏调用(`CALL("User32", "GetWindowTextLengthA", "JJ", ${窗口句柄})`);
  82.         let 缓冲区大小=窗口标题长度+1,窗口标题="";
  83.         const 内存地址 = 执行宏调用(`CALL("Kernel32", "VirtualAlloc", "JJJJJ", 0, ${缓冲区大小}, ${0x3000}, 4)`);        //申请内存
  84.         let 标题长度=执行宏调用(`CALL("User32", "GetWindowTextA", "JJJJ", ${窗口句柄},${内存地址},${窗口标题长度+1})`);
  85.         if(标题长度){窗口标题=内存读取字符串(内存地址);}
  86.         执行宏调用(`CALL("Kernel32", "VirtualFree", "JJJJ", ${内存地址}, 0, ${0x8000})`);        //释放内存
  87.         return 窗口标题;
  88. }
  89. function 获取窗口类名(窗口句柄){
  90.         const 执行宏调用=ExecuteExcel4Macro;
  91.         let 缓冲区大小=256,类名="";        //类名最长255
  92.         const 内存地址=执行宏调用(`CALL("Kernel32","VirtualAlloc","JJJJJ",0,${缓冲区大小},${0x3000},4)`);        //申请内存
  93.         let 类名长度=执行宏调用(`CALL("User32","GetClassNameA","JJJJ",${窗口句柄},${内存地址},${缓冲区大小})`);
  94.         if(类名长度){窗口类名=内存读取字符串(内存地址);}
  95.         执行宏调用(`CALL("Kernel32","VirtualFree","JJJJ",${内存地址},0,${0x8000})`);        //释放内存
  96.         return 窗口类名;
  97. }
  98. function 获取窗口坐标(窗口句柄){        //返回坐标数组:左上右下
  99.         const 执行宏调用=ExecuteExcel4Macro;
  100.         let 内存地址=申请虚拟内存(16);
  101.         let 结果=执行宏调用(`CALL("User32","GetWindowRect","JJJ",${窗口句柄},${内存地址})`);
  102.         let 数组缓冲=内存读取数据(内存地址,16);
  103.         释放虚拟内存(内存地址);
  104.         let 坐标数组=缓冲转数组(数组缓冲);
  105.         return 坐标数组;
  106. }
  107. function 内存读取字符串(内存地址){        //返回字符串
  108.         const 执行宏调用=ExecuteExcel4Macro,段长度=127;
  109.         const 总字节=执行宏调用(`CALL("Kernel32","lstrlenA","JJ",${内存地址})`);        //内存文本字节数
  110.         let 偏移字节=0,文本字符串=分段文本='';
  111.         while(偏移字节<总字节){        //返回字符串F。        //返回超255字节时,也需要分段操作
  112.                 分段文本=执行宏调用(`CALL("Kernel32","lstrcpynW","FFJJ","",${内存地址+偏移字节},${段长度})`);
  113.                 偏移字节+=分段文本.replace(/[^\x00-\xff]/g,'xx').length;        //计算字符串字节数
  114.                 文本字符串+=分段文本;
  115.         }
  116.         return 文本字符串;
  117. }
  118. function 内存读取数据(内存地址,字节数){        //返回数组缓冲
  119.         const 执行宏调用=ExecuteExcel4Macro;
  120.         let 偏移,i,读取字节=[],读出数据;
  121.         for(偏移=i=0;偏移<字节数;i++){
  122.                 if(字节数-偏移>=4){读取字节[i]=4;偏移+=4;}
  123.                 else{if(字节数-偏移>=2){读取字节[i]=2;偏移+=2;}
  124.                 else{if(字节数-偏移==1){读取字节[i]=1;偏移++;}}}
  125.         }
  126.         const 数组缓冲=new ArrayBuffer(字节数);        //用于存储读出的数据
  127.         const 数据操作=new DataView(数组缓冲);
  128.         for(偏移=i=0;偏移<字节数;i++){        //库Kernel32.dll和NtDll.dll里都有RtlMoveMemory        //读出
  129.                 读出数据=执行宏调用(`CALL("Kernel32","RtlMoveMemory","1NJJ",${内存地址},${内存地址+偏移},${读取字节[i]})`);
  130.                 if(读取字节[i]==4){数据操作.setInt32(偏移,读出数据,true);偏移+=4;}
  131.                 else{if(读取字节[i]==2){数据操作.setInt16(偏移,读出数据,true);偏移+=2;}
  132.                 else{if(读取字节[i]==1){数据操作.setInt8(偏移,读出数据,true);偏移++;}}}
  133.         }
  134.         return 数组缓冲;        //返回
  135. }
  136. function 缓冲转数组(数组缓冲){        //返回数组[]
  137.         let 总字节=数组缓冲.byteLength;
  138.         let 组数=Math.ceil(总字节/4);
  139.         const 数据操作=new DataView(数组缓冲);
  140.         let 数组=[];
  141.         for(let i=0;i<组数;i++){
  142.                 数组[i]=数据操作.getInt32(i*4,true);
  143.         }
  144.         return 数组;
  145. }
  146. function 申请虚拟内存(字节数){        //返回内存地址
  147.         const 执行宏调用=ExecuteExcel4Macro;
  148.         const 内存地址=执行宏调用(`CALL("Kernel32","VirtualAlloc","JJJJJ",0,${字节数},${0x3000},4)`);
  149.         return 内存地址;
  150. }
  151. function 释放虚拟内存(内存地址){
  152.         const 执行宏调用=ExecuteExcel4Macro;
  153.         执行宏调用(`CALL("Kernel32","VirtualFree","JJJJ",${内存地址},0,${0x8000})`);
  154. }
复制代码


 楼主| 发表于 昨天 22:41 | 显示全部楼层

增加文本编辑框内容的识别,类为Edit

  1. function 寻根开枝叶测试(){        //找到根顺枝到叶
  2.         let 窗口句柄=鼠标所指窗口句柄();
  3.         console.clear();
  4.         while(窗口句柄){        //收藏
  5.                 var 句柄=窗口句柄;
  6.                 let 窗口信息=获取窗口信息(窗口句柄);
  7.                 窗口信息显示(窗口信息,"","窗口");
  8.                 窗口句柄=父窗口(窗口句柄);
  9.         }
  10.         const 根句柄=句柄,根序=1;
  11.         console.log("\t["+根序+"]根句柄:"+根句柄);
  12.         //生长
  13.         let 枝句柄=根句柄;
  14.         子弟窗口(枝句柄,0,根序,0);
  15. }
  16. function 父窗口(窗口句柄){        //返回父窗口句柄
  17.         const 执行宏调用=ExecuteExcel4Macro;
  18.         父句柄=执行宏调用(`CALL("User32","GetParent","JJ",${窗口句柄})`);
  19.         return 父句柄;
  20. }
  21. function 子弟窗口(父句柄,兄句柄,父祖序,兄弟序){        //显示窗口信息树
  22.         let 子句柄=下个子窗口(父句柄,兄句柄);
  23.         while(子句柄){
  24.                 兄弟序++;let 传承=父祖序+'.'+兄弟序;
  25.                 let 子窗口信息=获取窗口信息(子句柄);
  26.                 窗口信息显示(子窗口信息,"["+传承+"]","");
  27.                 子弟窗口(子句柄,0,传承,0);        //---回溯---//
  28.                 子句柄=下个子窗口(父句柄,子句柄);
  29.         }
  30. }
  31. function 下个子窗口(父句柄,兄句柄){return 下一个子窗口(父句柄,兄句柄,0,0);}
  32. function 下一个子窗口(父句柄,上个子句柄,标题,类){
  33.         const 执行宏调用=ExecuteExcel4Macro;
  34.         var 子句柄;
  35.         if(!标题){        //标题为0               
  36.                 if(!类){        //类为0
  37.                         子句柄=执行宏调用(`CALL("User32","FindWindowExA","JJJJJ",${父句柄},${上个子句柄},0,0)`);
  38.                 }else{
  39.                         子句柄=执行宏调用(`CALL("User32","FindWindowExA","JJJFJ",${父句柄},${上个子句柄},"${类}",0)`);
  40.                 }
  41.         }else{
  42.                 if(!类){        //类为0
  43.                         子句柄=执行宏调用(`CALL("User32","FindWindowExA","JJJJF",${父句柄},${上个子句柄},0,"${标题}")`);
  44.                 }else{
  45.                         子句柄=执行宏调用(`CALL("User32","FindWindowExA","JJJFF",${父句柄},${上个子句柄},"${类}","${标题}")`);
  46.                 }
  47.         }
  48.         return 子句柄;
  49. }
  50. function 鼠标所指窗口句柄(){        //返回窗口句柄
  51.         const 执行宏调用=ExecuteExcel4Macro;
  52.         let 鼠标指针坐标=获取鼠标位置();        //===调用函数===/
  53.         let 水平=鼠标指针坐标[0],垂直=鼠标指针坐标[1];        //鼠标指针处窗口句柄        //扩展了一个参数
  54.         let 窗口句柄=执行宏调用(`CALL("User32", "WindowFromPoint", "JJJ", ${水平},${垂直})`);
  55.         return 窗口句柄;
  56. }
  57. function 获取鼠标位置(){        //返回坐标数组[x,y]
  58.         const 执行宏调用=ExecuteExcel4Macro;
  59.         var 坐标结构=执行宏调用(`CALL("User32","GetCursorPos","1E",0)`);        //参数:4+4字节坐标结构
  60.         const 缓冲区=new ArrayBuffer(8); //8字节对应64位
  61.         const 数据操作=new DataView(缓冲区);        //操作对象
  62.         数据操作.setFloat64(0,坐标结构);        //(操作)写入64位数
  63.         let 坐标=[];
  64.         坐标[0]=数据操作.getInt32(4);        //取32位坐标x
  65.         坐标[1]=数据操作.getInt32(0);        //取32位坐标y
  66.         return 坐标;
  67. }
  68. function 获取窗口信息(窗口句柄){        //返回数组[句柄,标题,类,坐标]
  69.         let 窗口标题=获取窗口标题(窗口句柄);
  70.         let 窗口类名=获取窗口类名(窗口句柄);
  71.         let 窗口内容=获取窗口内容(窗口句柄);
  72.         let 窗口坐标=获取窗口坐标(窗口句柄);
  73.         return [窗口句柄,窗口标题,窗口类名,窗口内容,窗口坐标];
  74. }
  75. function 窗口信息显示(窗口信息,目录,说明){        //句柄、标题、类、坐标
  76.         let 窗口句柄=窗口信息[0],窗口标题=窗口信息[1];
  77.         let 窗口类名=窗口信息[2],编辑文本=窗口信息[3],窗口坐标=窗口信息[4];
  78.         console.log(目录+说明+"句柄:"+窗口句柄+"\t"+说明+"标题:"+窗口标题+"\t"+说明+"类名:"+窗口类名+"\t"+说明+"内容:"+编辑文本+"\t"+说明+"坐标:"+窗口坐标);
  79. }
  80. function 获取窗口标题(窗口句柄){
  81.         const 执行宏调用=ExecuteExcel4Macro;
  82.         let 窗口标题长度=执行宏调用(`CALL("User32", "GetWindowTextLengthA", "JJ", ${窗口句柄})`);
  83.         let 缓冲区大小=窗口标题长度+1,窗口标题="";
  84.         const 内存地址 = 执行宏调用(`CALL("Kernel32", "VirtualAlloc", "JJJJJ", 0, ${缓冲区大小}, ${0x3000}, 4)`);        //申请内存
  85.         let 标题长度=执行宏调用(`CALL("User32", "GetWindowTextA", "JJJJ", ${窗口句柄},${内存地址},${窗口标题长度+1})`);
  86.         if(标题长度){窗口标题=内存读取字符串(内存地址);}
  87.         执行宏调用(`CALL("Kernel32", "VirtualFree", "JJJJ", ${内存地址}, 0, ${0x8000})`);        //释放内存
  88.         return 窗口标题;
  89. }
  90. function 获取窗口类名(窗口句柄){
  91.         const 执行宏调用=ExecuteExcel4Macro;
  92.         let 缓冲区大小=256,窗口类名="";        //类名最长255
  93.         const 内存地址=执行宏调用(`CALL("Kernel32","VirtualAlloc","JJJJJ",0,${缓冲区大小},${0x3000},4)`);        //申请内存
  94.         let 类名长度=执行宏调用(`CALL("User32","GetClassNameA","JJJJ",${窗口句柄},${内存地址},${缓冲区大小})`);
  95.         if(类名长度){窗口类名=内存读取字符串(内存地址);}
  96.         执行宏调用(`CALL("Kernel32","VirtualFree","JJJJ",${内存地址},0,${0x8000})`);        //释放内存
  97.         return 窗口类名;
  98. }
  99. function 获取窗口内容(编辑框句柄){        //一般为编辑文本框,类:Edit
  100.         const 执行宏调用=ExecuteExcel4Macro;
  101.         let 编辑框内容="",获取文本长度=0xE,获取文本=0xD;        //消息含义
  102.         var 内容长度=执行宏调用(`CALL("User32", "SendMessageA", "JJJJJ", ${编辑框句柄},${获取文本长度},0,0)`);
  103.         if(内容长度){
  104.                 let 缓冲区大小=内容长度+1;
  105.                 const 内存地址=执行宏调用(`CALL("Kernel32","VirtualAlloc","JJJJJ",0,${缓冲区大小},${0x3000},4)`);        //申请内存
  106.                 var 获取结果=执行宏调用(`CALL("User32", "SendMessageA", "JJJJJ", ${编辑框句柄},${获取文本},${内容长度+1},${内存地址})`);
  107.                 编辑框内容=内存读取字符串(内存地址);
  108.                 执行宏调用(`CALL("Kernel32","VirtualFree","JJJJ",${内存地址},0,${0x8000})`);        //释放内存
  109.         }
  110.         return 编辑框内容;
  111. }
  112. function 获取窗口坐标(窗口句柄){        //返回坐标数组:左上右下
  113.         const 执行宏调用=ExecuteExcel4Macro;
  114.         let 内存地址=申请虚拟内存(16);
  115.         let 结果=执行宏调用(`CALL("User32","GetWindowRect","JJJ",${窗口句柄},${内存地址})`);
  116.         let 数组缓冲=内存读取数据(内存地址,16);
  117.         释放虚拟内存(内存地址);
  118.         let 坐标数组=缓冲转数组(数组缓冲);
  119.         return 坐标数组;
  120. }
  121. function 内存读取字符串(内存地址){        //返回字符串
  122.         const 执行宏调用=ExecuteExcel4Macro,段长度=127;
  123.         const 总字节=执行宏调用(`CALL("Kernel32","lstrlenA","JJ",${内存地址})`);        //内存文本字节数
  124.         let 偏移字节=0,文本字符串=分段文本='';
  125.         while(偏移字节<总字节){        //返回字符串F。        //返回超255字节时,也需要分段操作
  126.                 分段文本=执行宏调用(`CALL("Kernel32","lstrcpynW","FFJJ","",${内存地址+偏移字节},${段长度})`);
  127.                 偏移字节+=分段文本.replace(/[^\x00-\xff]/g,'xx').length;        //计算字符串字节数
  128.                 文本字符串+=分段文本;
  129.         }
  130.         return 文本字符串;
  131. }
  132. function 内存读取数据(内存地址,字节数){        //返回数组缓冲
  133.         const 执行宏调用=ExecuteExcel4Macro;
  134.         let 偏移,i,读取字节=[],读出数据;
  135.         for(偏移=i=0;偏移<字节数;i++){
  136.                 if(字节数-偏移>=4){读取字节[i]=4;偏移+=4;}
  137.                 else{if(字节数-偏移>=2){读取字节[i]=2;偏移+=2;}
  138.                 else{if(字节数-偏移==1){读取字节[i]=1;偏移++;}}}
  139.         }
  140.         const 数组缓冲=new ArrayBuffer(字节数);        //用于存储读出的数据
  141.         const 数据操作=new DataView(数组缓冲);
  142.         for(偏移=i=0;偏移<字节数;i++){        //库Kernel32.dll和NtDll.dll里都有RtlMoveMemory        //读出
  143.                 读出数据=执行宏调用(`CALL("Kernel32","RtlMoveMemory","1NJJ",${内存地址},${内存地址+偏移},${读取字节[i]})`);
  144.                 if(读取字节[i]==4){数据操作.setInt32(偏移,读出数据,true);偏移+=4;}
  145.                 else{if(读取字节[i]==2){数据操作.setInt16(偏移,读出数据,true);偏移+=2;}
  146.                 else{if(读取字节[i]==1){数据操作.setInt8(偏移,读出数据,true);偏移++;}}}
  147.         }
  148.         return 数组缓冲;        //返回
  149. }
  150. function 缓冲转数组(数组缓冲){        //返回数组[]
  151.         let 总字节=数组缓冲.byteLength;
  152.         let 组数=Math.ceil(总字节/4);
  153.         const 数据操作=new DataView(数组缓冲);
  154.         let 数组=[];
  155.         for(let i=0;i<组数;i++){
  156.                 数组[i]=数据操作.getInt32(i*4,true);
  157.         }
  158.         return 数组;
  159. }
  160. function 申请虚拟内存(字节数){        //返回内存地址
  161.         const 执行宏调用=ExecuteExcel4Macro;
  162.         const 内存地址=执行宏调用(`CALL("Kernel32","VirtualAlloc","JJJJJ",0,${字节数},${0x3000},4)`);
  163.         return 内存地址;
  164. }
  165. function 释放虚拟内存(内存地址){
  166.         const 执行宏调用=ExecuteExcel4Macro;
  167.         执行宏调用(`CALL("Kernel32","VirtualFree","JJJJ",${内存地址},0,${0x8000})`);
  168. }
复制代码


回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2026-5-1 03:45

Powered by Discuz! X5.0

© 2001-2026 Discuz! Team.

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