原脚本的核心问题有两个,一是用鼠标指向取窗口句柄的方式不稳定,每次启动都要手动把鼠标移到目标网页窗口上,脚本运行过程中还会主动把网页窗口切到前台,没办法真正后台运行,二是所有操作都是固定坐标加重复代码,改一个参数要改一堆地方,也没法同时开多个网页窗口跑脚本,改写的时候针对这几个问题逐一优化就能实现稳定后台多开。
改写第一步,要把窗口句柄的获取方式从鼠标指向改成按网页标题或者进程名批量匹配获取。不要用Window.MousePoint(),改用Window.Find()或者Window.FindEx(),指定窗口的标题特征或者类名来精准定位浏览器窗口。比如你的网页游戏标题固定带某个后缀,就可以用模糊匹配的方式把所有符合条件的浏览器窗口句柄都找出来,存到一个数组里,后面循环遍历这个数组给每个窗口发后台操作,这样就能支持同时开多个网页同时运行。如果是同一款游戏开多个小号,窗口标题前面可以加前缀区分,比如小号1、小号2,脚本根据不同前缀分别匹配,每个窗口对应独立的操作循环,互不干扰。
改写第二步,要用稳定的后台插件替换原生的Bkgnd插件。按键精灵自带的Bkgnd后台插件兼容性很差,很多浏览器的窗口收不到后台消息,尤其是基于Chromium内核的浏览器,后台点击经常失效,还会强制把窗口调到前台,就是因为这个插件的消息投递方式会激活窗口。换成大漠插件或者361度后台插件就能解决这个问题,这两个插件的消息投递模式是直接发消息给窗口过程,不会强制激活窗口,窗口最小化或者被其他窗口完全挡住都能正常接收到点击和移动指令,真正实现后台静默运行。绑定窗口的时候选择dx模式或者正常模式的后台绑定,绑定之后整个脚本运行过程中窗口都不会主动弹到前台,就算开着别的软件工作,脚本也会在后台默默跑,完全不影响前台操作。
改写第三步,把重复的右键点击代码封装成循环或者子程序,不要每一次点击都写一遍MoveTo加RightClick加Delay。比如第一个坐标要点6次右键,就写个For循环6次,循环体里只写一次点击和延时,后面要改点击次数或者延时时间,只改循环次数和一个延时参数就行,代码量能减少一大半,也不容易写错。不同坐标点的重复点击可以封装成一个通用的右键连点子程序,传入窗口句柄、横坐标、纵坐标、点击次数三个参数,调用一次就能完成指定次数的点击,后面要加新的点位直接调用子程序就行,不用再重复写一堆重复代码。
改写第四步,增加窗口存在性校验,避免脚本卡在无效窗口上。每次给窗口发操作之前,先判断一下这个窗口句柄还在不在,如果用户不小心把网页关了,脚本自动跳过这个窗口,不要一直往无效句柄发消息导致报错。可以在每次循环开头加一句判断,调用Window.IsWindowExist(),如果窗口不存在就把它从数组里移除,后续循环不再处理这个窗口。如果要做更稳定的版本,可以加窗口重连机制,窗口关掉之后自动重新寻找符合标题特征的新窗口,重新绑定继续运行,不用人工重启脚本。
改写第五步,要解决网页最小化也能正常运行的问题。绑定窗口的时候,一定要选图色模式和输入模式都支持后台的绑定模式,不要选只支持前台的模式。比如用大漠插件的话,绑定模式选“dx2”或者“normal”,输入模式选“windows”消息模式,这两种模式下就算浏览器窗口最小化,后台消息也能正常投递,点击、移动、按键操作都有效,不会出现最小化就不动的情况。注意不要用硬件模拟模式,硬件模式必须窗口在前台才能生效,最小化之后就完全失效了。如果是浏览器内核的游戏,绑定的目标句柄要取到浏览器里面的渲染控件句柄,不要只绑外层的浏览器主窗口,不然经常会出现点击没反应的情况,可以用FindEx一层一层往下找子窗口,找到真正接收点击的那个控件句柄再绑定,稳定性会高很多。
以下是改写后的完整多开后台脚本框架,适配多个网页窗口同时运行,最小化不影响,窗口不会主动弹到前台:
// 网页游戏后台多开脚本 按键精灵+大漠插件版
PutAttachment "c:\test_game", "."
Set dm = createobject("dm.dmsoft")
dm_ret = dm.SetPath("c:\test_game")
// 配置参数 根据实际情况修改
Dim 窗口标题关键字 = "我的网页游戏"
Dim 点击延时 = 500
Dim 总等待时间 = 54000
// 点击点位配置 每个元素为 横坐标|纵坐标|点击次数
Dim 点位数组
点位数组 = Array("36|240|6","72|240|5")
// 批量获取所有符合标题的网页窗口句柄
Dim hwnds, 窗口数量
hwnds = dm.EnumWindow(0, 窗口标题关键字, "", 1 + 4 + 16)
窗口句柄数组 = Split(hwnds, ",")
窗口数量 = UBound(窗口句柄数组) + 1
If 窗口数量 = 0 Then
MsgBox "没有找到符合标题的游戏窗口,请先打开游戏"
EndScript
End If
// 定义窗口绑定数组
Dim 绑定数组()
ReDim 绑定数组(窗口数量 - 1)
// 批量绑定所有窗口 选择纯后台模式 不会弹前台
For i = 0 To 窗口数量 - 1
hwnd = Clng(窗口句柄数组(i))
// 选择 dx2 图色模式 + windows 消息输入模式 完全后台 不激活窗口
dm_ret = dm.BindWindow(hwnd, "dx2", "windows", "windows", 0)
绑定数组(i) = dm_ret
Next
// 主循环 所有窗口并行执行操作
Do
For i = 0 To 窗口数量 - 1
hwnd = Clng(窗口句柄数组(i))
If dm.IsWindow(hwnd) = 0 Then
// 窗口已关闭 跳过
Goto 下一个窗口
End If
// 第一步 等待指定时间
Delay 总等待时间
// 第二步 点击左上角第一个固定坐标
dm.MoveTo 36, 240
Delay 100
dm.RightClick 36, 240
Delay 点击延时
dm.RightClick 36, 240
Delay 点击延时
dm.RightClick 36, 240
Delay 点击延时
dm.RightClick 36, 240
Delay 点击延时
dm.RightClick 36, 240
Delay 点击延时
dm.RightClick 36, 240
Delay 点击延时
// 第三步 点击第二个坐标点
dm.MoveTo 72, 240
Delay 100
dm.RightClick 72, 240
Delay 点击延时
dm.RightClick 72, 240
Delay 点击延时
dm.RightClick 72, 240
Delay 点击延时
dm.RightClick 72, 240
Delay 点击延时
dm.RightClick 72, 240
Delay 点击延时
Rem 下一个窗口
Next
Loop
// 脚本退出前解绑所有窗口
Sub OnScriptExit
For i = 0 To 窗口数量 - 1
hwnd = Clng(窗口句柄数组(i))
dm.UnBindWindow hwnd
Next
End Sub
要确保窗口不弹到前台,有几个细节一定要注意。一是不要在脚本里调用任何激活窗口的命令,比如Window.Active、Window.SetTop这些,哪怕是为了找坐标也不要用,后台模式下坐标是相对于窗口客户区的,不用激活也能精准点击。二是不要用前台的鼠标键盘模拟命令,所有操作都要用绑定后的后台插件命令发消息,不要混用前台命令,一调用前台命令窗口就会弹出来。三是不要用找图找色的前台模式,图色获取也要用后台插件的后台图色模式,后台取色不会影响窗口状态。四是浏览器本身不要设置总在最前,不然哪怕脚本不主动激活,窗口也可能因为浏览器自身机制跳到前面,把浏览器的置顶选项关掉就行。
多开运行的时候,每个网页窗口的分辨率要统一,最好都设成一样的大小,因为坐标是按窗口客户区计算的,窗口大小不一样,同一个坐标点对应的位置就不一样,会点偏。可以在绑定窗口之后,用插件的SetWindowSize命令把所有窗口都设成固定的宽高,比如800x600,这样所有窗口的坐标都通用,不用每个窗口单独配坐标。开多少个窗口都行,只要电脑性能扛得住,脚本会按顺序给每个窗口发操作,每个窗口独立运行互不影响,不用开多个按键精灵实例,一个脚本就能管几十个窗口。
常见问题的处理方式也很简单。如果后台点击没反应,先检查绑定模式对不对,是不是选了只支持前台的模式,换一种绑定模式试试,不同浏览器适配的模式不一样,Chrome内核的浏览器dx2模式一般都能用,不行就试normal模式。如果最小化就失效,说明图色模式选的是前台模式,换成dx系列的后台图色模式就行。如果只有第一个窗口能运行,后面的窗口不动,检查一下循环逻辑是不是只处理了第一个句柄,数组遍历是不是写对了。如果脚本运行过程中窗口偶尔弹出来,检查代码里是不是不小心混了前台命令,或者插件绑定时加了激活窗口的参数,把那个参数去掉就可以了。
改写第一步,要把窗口句柄的获取方式从鼠标指向改成按网页标题或者进程名批量匹配获取。不要用Window.MousePoint(),改用Window.Find()或者Window.FindEx(),指定窗口的标题特征或者类名来精准定位浏览器窗口。比如你的网页游戏标题固定带某个后缀,就可以用模糊匹配的方式把所有符合条件的浏览器窗口句柄都找出来,存到一个数组里,后面循环遍历这个数组给每个窗口发后台操作,这样就能支持同时开多个网页同时运行。如果是同一款游戏开多个小号,窗口标题前面可以加前缀区分,比如小号1、小号2,脚本根据不同前缀分别匹配,每个窗口对应独立的操作循环,互不干扰。
改写第二步,要用稳定的后台插件替换原生的Bkgnd插件。按键精灵自带的Bkgnd后台插件兼容性很差,很多浏览器的窗口收不到后台消息,尤其是基于Chromium内核的浏览器,后台点击经常失效,还会强制把窗口调到前台,就是因为这个插件的消息投递方式会激活窗口。换成大漠插件或者361度后台插件就能解决这个问题,这两个插件的消息投递模式是直接发消息给窗口过程,不会强制激活窗口,窗口最小化或者被其他窗口完全挡住都能正常接收到点击和移动指令,真正实现后台静默运行。绑定窗口的时候选择dx模式或者正常模式的后台绑定,绑定之后整个脚本运行过程中窗口都不会主动弹到前台,就算开着别的软件工作,脚本也会在后台默默跑,完全不影响前台操作。
改写第三步,把重复的右键点击代码封装成循环或者子程序,不要每一次点击都写一遍MoveTo加RightClick加Delay。比如第一个坐标要点6次右键,就写个For循环6次,循环体里只写一次点击和延时,后面要改点击次数或者延时时间,只改循环次数和一个延时参数就行,代码量能减少一大半,也不容易写错。不同坐标点的重复点击可以封装成一个通用的右键连点子程序,传入窗口句柄、横坐标、纵坐标、点击次数三个参数,调用一次就能完成指定次数的点击,后面要加新的点位直接调用子程序就行,不用再重复写一堆重复代码。
改写第四步,增加窗口存在性校验,避免脚本卡在无效窗口上。每次给窗口发操作之前,先判断一下这个窗口句柄还在不在,如果用户不小心把网页关了,脚本自动跳过这个窗口,不要一直往无效句柄发消息导致报错。可以在每次循环开头加一句判断,调用Window.IsWindowExist(),如果窗口不存在就把它从数组里移除,后续循环不再处理这个窗口。如果要做更稳定的版本,可以加窗口重连机制,窗口关掉之后自动重新寻找符合标题特征的新窗口,重新绑定继续运行,不用人工重启脚本。
改写第五步,要解决网页最小化也能正常运行的问题。绑定窗口的时候,一定要选图色模式和输入模式都支持后台的绑定模式,不要选只支持前台的模式。比如用大漠插件的话,绑定模式选“dx2”或者“normal”,输入模式选“windows”消息模式,这两种模式下就算浏览器窗口最小化,后台消息也能正常投递,点击、移动、按键操作都有效,不会出现最小化就不动的情况。注意不要用硬件模拟模式,硬件模式必须窗口在前台才能生效,最小化之后就完全失效了。如果是浏览器内核的游戏,绑定的目标句柄要取到浏览器里面的渲染控件句柄,不要只绑外层的浏览器主窗口,不然经常会出现点击没反应的情况,可以用FindEx一层一层往下找子窗口,找到真正接收点击的那个控件句柄再绑定,稳定性会高很多。
以下是改写后的完整多开后台脚本框架,适配多个网页窗口同时运行,最小化不影响,窗口不会主动弹到前台:
// 网页游戏后台多开脚本 按键精灵+大漠插件版
PutAttachment "c:\test_game", "."
Set dm = createobject("dm.dmsoft")
dm_ret = dm.SetPath("c:\test_game")
// 配置参数 根据实际情况修改
Dim 窗口标题关键字 = "我的网页游戏"
Dim 点击延时 = 500
Dim 总等待时间 = 54000
// 点击点位配置 每个元素为 横坐标|纵坐标|点击次数
Dim 点位数组
点位数组 = Array("36|240|6","72|240|5")
// 批量获取所有符合标题的网页窗口句柄
Dim hwnds, 窗口数量
hwnds = dm.EnumWindow(0, 窗口标题关键字, "", 1 + 4 + 16)
窗口句柄数组 = Split(hwnds, ",")
窗口数量 = UBound(窗口句柄数组) + 1
If 窗口数量 = 0 Then
MsgBox "没有找到符合标题的游戏窗口,请先打开游戏"
EndScript
End If
// 定义窗口绑定数组
Dim 绑定数组()
ReDim 绑定数组(窗口数量 - 1)
// 批量绑定所有窗口 选择纯后台模式 不会弹前台
For i = 0 To 窗口数量 - 1
hwnd = Clng(窗口句柄数组(i))
// 选择 dx2 图色模式 + windows 消息输入模式 完全后台 不激活窗口
dm_ret = dm.BindWindow(hwnd, "dx2", "windows", "windows", 0)
绑定数组(i) = dm_ret
Next
// 主循环 所有窗口并行执行操作
Do
For i = 0 To 窗口数量 - 1
hwnd = Clng(窗口句柄数组(i))
If dm.IsWindow(hwnd) = 0 Then
// 窗口已关闭 跳过
Goto 下一个窗口
End If
// 第一步 等待指定时间
Delay 总等待时间
// 第二步 点击左上角第一个固定坐标
dm.MoveTo 36, 240
Delay 100
dm.RightClick 36, 240
Delay 点击延时
dm.RightClick 36, 240
Delay 点击延时
dm.RightClick 36, 240
Delay 点击延时
dm.RightClick 36, 240
Delay 点击延时
dm.RightClick 36, 240
Delay 点击延时
dm.RightClick 36, 240
Delay 点击延时
// 第三步 点击第二个坐标点
dm.MoveTo 72, 240
Delay 100
dm.RightClick 72, 240
Delay 点击延时
dm.RightClick 72, 240
Delay 点击延时
dm.RightClick 72, 240
Delay 点击延时
dm.RightClick 72, 240
Delay 点击延时
dm.RightClick 72, 240
Delay 点击延时
Rem 下一个窗口
Next
Loop
// 脚本退出前解绑所有窗口
Sub OnScriptExit
For i = 0 To 窗口数量 - 1
hwnd = Clng(窗口句柄数组(i))
dm.UnBindWindow hwnd
Next
End Sub
要确保窗口不弹到前台,有几个细节一定要注意。一是不要在脚本里调用任何激活窗口的命令,比如Window.Active、Window.SetTop这些,哪怕是为了找坐标也不要用,后台模式下坐标是相对于窗口客户区的,不用激活也能精准点击。二是不要用前台的鼠标键盘模拟命令,所有操作都要用绑定后的后台插件命令发消息,不要混用前台命令,一调用前台命令窗口就会弹出来。三是不要用找图找色的前台模式,图色获取也要用后台插件的后台图色模式,后台取色不会影响窗口状态。四是浏览器本身不要设置总在最前,不然哪怕脚本不主动激活,窗口也可能因为浏览器自身机制跳到前面,把浏览器的置顶选项关掉就行。
多开运行的时候,每个网页窗口的分辨率要统一,最好都设成一样的大小,因为坐标是按窗口客户区计算的,窗口大小不一样,同一个坐标点对应的位置就不一样,会点偏。可以在绑定窗口之后,用插件的SetWindowSize命令把所有窗口都设成固定的宽高,比如800x600,这样所有窗口的坐标都通用,不用每个窗口单独配坐标。开多少个窗口都行,只要电脑性能扛得住,脚本会按顺序给每个窗口发操作,每个窗口独立运行互不影响,不用开多个按键精灵实例,一个脚本就能管几十个窗口。
常见问题的处理方式也很简单。如果后台点击没反应,先检查绑定模式对不对,是不是选了只支持前台的模式,换一种绑定模式试试,不同浏览器适配的模式不一样,Chrome内核的浏览器dx2模式一般都能用,不行就试normal模式。如果最小化就失效,说明图色模式选的是前台模式,换成dx系列的后台图色模式就行。如果只有第一个窗口能运行,后面的窗口不动,检查一下循环逻辑是不是只处理了第一个句柄,数组遍历是不是写对了。如果脚本运行过程中窗口偶尔弹出来,检查代码里是不是不小心混了前台命令,或者插件绑定时加了激活窗口的参数,把那个参数去掉就可以了。

