多线程同步操作多个窗口.doc_第1页
多线程同步操作多个窗口.doc_第2页
多线程同步操作多个窗口.doc_第3页
多线程同步操作多个窗口.doc_第4页
多线程同步操作多个窗口.doc_第5页
已阅读5页,还剩6页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

多线程同步操作多个窗口RunApp notepad.exeRunApp notepad.exeRunApp notepad.exeDelay 2000Dimenv temp_Hwndtemp_Hwnd = 0Dim str, arr, istr = Plugin.Window.Search(无标题 - 记事本)arr = Split(str, |)For i = 0 To UBound(arr) - 1 temp_Hwnd = Plugin.Window.FindEx(arr(i), 0, Edit, 0) BeginThread WriteString While temp_Hwnd 0判断多线程已经启动完毕,继续循环下一个。 Delay 500 WendNextEndScriptFunction WriteString() Dim str, Hwnd Hwnd = temp_Hwnd temp_Hwnd = 0 Do str = WaitKey If Hwnd Plugin.Window.GetKeyFocusWnd Then Call Plugin.Bkgnd.KeyPress(Hwnd, str) End If LoopEnd Function多线程多开窗口同步执行与子线程间的数值如何传递:1. Dimenv IsThread, i2. Dim arr_Thread()3. For i = 0 To 24. IsThread = False未启动线程5. Redim Preserve arr_Thread(i)6. arr_Thread(i) = BeginThread(EnterThread)7. While IsThread = False未启动成功,等待中8. Delay 5009. Wend10. 跳出循环说明 IsThread = True,已经执行到了,循环继续启动下一个11. Next12. EndScript结束主线,但子线程还会继续运行13. 函数调用/14. Function EnterThread()15. Dim n16. n = i17. IsThread = True18. Do19. TracePrint 运行线程: & n20. Delay 50021. Loop22. End Function多线程运行中单独停止某个子线程演示:1. 环境变量声明2. Dimenv Hwnd, IsThread3. IsThread = False4. Do5. Hwnd = Plugin.Window.Find(Notepad, 无标题 - 记事本)6. If Hwnd = 0 Then7. RunApp notepad.exe : Delay 20008. TracePrint 运行记事本9. End If10. Loop While Hwnd = 011. 获得记事本中输入子窗口句柄,以便按键输入内容12. Hwnd = Plugin.Window.FindEx(Hwnd, 0, Edit, 0)13. 全局变量声明14. Dim IdThread15. 主循环16. Do17. If WaitKey() = 81 Then18. If IsThread = False Then19. IdThread = BeginThread(WriteString)20. Do21. TracePrint 等待线程启动!22. Delay 50023. Loop While IsThread = False24. TracePrint 线程启动成功!25. Else26. TracePrint 线程停止操作!27. StopThread IdThread28. IsThread = False29. End If30. End If31. Loop32. 以下是函数区域33. Function WriteString()34. IsThread = True35. Do36. Call Plugin.Bkgnd.KeyPress(Hwnd, 65)37. Delay 50038. Loop39. End Function主线程逐个开启子线程五开操作演示:1. 五开操作2. Dim str_Hwnd3. str_Hwnd = vbNullString记录都有哪些窗口句柄在运行4. DimEnv IsHwnd5. IsHwnd = 06. For i_win = 0 To 47. Do8. RunApp notepad.exe9. str = Plugin.Window.Search(无标题 - 记事本)10. arr = Split(str, |)11. If str vbNullString Then12. For i = 0 To UBound(arr) - 113. If InStr(str_Hwnd, arr(i) = 0 Then14. IsHwnd = arr(i)15. str_Hwnd = str_Hwnd & arr(i) & |16. Exit For17. End If 18. Next19. Else20. IsHwnd = arr(0)21. End If22. Loop While IsHwnd = 023. Call Plugin.Window.SetClientSize(IsHwnd, 300, 300)24. Call Plugin.Window.Move(IsHwnd, 300 * i_win, 0)25. BeginThread 后台喊话26. Do27. Delay 100028. Loop Until Hwnd = 029. Next30. EndScript31. Function 后台喊话()32. Dim Hwnd33. Hwnd = Plugin.Window.FindEx(IsHwnd, 0, Edit, 0)34. IsHwnd = 035. Do36. Call Plugin.Bkgnd.SendString(Hwnd, 文字测试)37. Call Plugin.Bkgnd.KeyPress(Hwnd, 13)38. Delay 50039. Loop40. End Function一、多线程是什么,可以干什么 一般来说,我们编写的脚本都是一条道走到黑,最多加点循环、判断和跳转,程序始终是按部就班的执行指定的命令,只能同时干一件工作,让它取色就取色,让它单击就单击,不能同时完成两项以上的工作。多线程的出现,是让脚本可以同时开展几项工作,在单击时,可以通过环境变量传过来取色子程序获得的坐标,而无需在每次单击命令前执行调用取色子程序。当然这只是一个很简单的例子,像这样简单的情况,是没必要弄个多线程的,如果非要弄出多线程处理,反而要考虑到同步的问题:这边要单击了,那边取色命令传过来的坐标值,是多长时间以前的?或者直接取色命令还没执行完,这边到底单击哪里呢? 有人说按键精灵的多线程是伪多线程,其实不管是真假多线程,对于电脑的CPU来说,同时只会做一件事情,只是说把各个线程传过来需要处理的东西按照时间先后和优先级的关系,排个队列挨个执行而已。就像你去食堂打饭,很多人排队打,但是打饭的师傅只有一个,关系好的可能能插个队。多核CPU大概是食堂有好几个窗口,这样的话,倒是有可能同时有几个同学在打饭。那么,我们假设要做的工作是让一个寝室的同学聚餐,可以派一个人去打饭(单线程),或者派几个人去打饭(多线程)。假设班长下达了命令:甲负责打菜,乙负责打饭,丙负责买汽水,其余的负责准备场地,那么什么时候开饭,应该要等到甲乙丙任务都完成了才行。可以约定时间,也可以让每个人报告。如果有一辆自行车可以用,那么甲乙丙三个人都可以骑,同时骑,也就相当与出现了三辆,谁的骑坏了都与别人的没关系。为了更好更快的完成人物,甲乙丙三人都可以同时拉剩下的人帮忙,比如丁,也会变成三个人,每个丁分身都与其他分身无关。好吧,不闲扯了,代码也不多贴,把我总结的规律直接写出来吧。 (一)首先要弄明白变量的作用域这个问题:在按键里,有这些规律: 1.在主体代码最前面(最好这么干,你非要在中间写一句dim,我也没办法)用dim定义的变量(统称外部变量),作用范围为全脚本,但是如果在子程序里面出现用dim显式定义的同名变量或者在子程序参数列表里的同名变量,那么在该子程序体内所用到的该变量,是内部变量,与外部变量无关; 2.子程序中可以用dim关键字定义内部变量,如果未定义的变量直接使用,默认为外部变量。 3.外部变量如果出现在子程序中,并且子程序中没有定义过同名的内部变量,在正常的调用中,按外部变量处理,但是如果在多线程中调用这个子程序,那么该变量会自动变成内部变量初始化掉,具体情况如下:1. Dim a /此处是否定义对多线程内部的变量a无影响2. BeginThread cd3. Sub cd4. Dim a5. /此处如果定义了,变量a为子程序cd的内部变量,6. /否则如果此处为定义,且子程序cs中未定义,则变量a为整个多线程的外部变量7. a = 238. Call cs(a)9. TracePrint a10. Call cs(a)11. TracePrint a12. End Sub13. Sub cs(b)14. Dim a15. /此处如果定义了,变量a在子程序cs内部永远都是内部变量16. /或者把b改成a,也是隐式的定义了一个内部变量a17. a=a+b 18. End Sub复制代码 4.在主题代码最前面用Global定义的是全局变量,作用范围多说同DimEnv环境变量,我猜这两个有一个可以在脚本之间交换数据。如果只是用于单脚本的多线程,可以看成一样的。这两个关键字都不能出现在子程序包括多线程的子程序中; 5.还有个大家关心的大漠等插件的绑定问题,规律如下:1. Set dm = CreateObject(dm.dmsoft)2. /此处绑定之后,程序主体中调用的子程序都可以使用大漠插件3. call cs4. BeginThread cd5. Sub cd6. Set dm = CreateObject(dm.dmsoft)7. /此处绑定之后,此线程调用的任何子程序都可以使用大漠插件8. Call cs9. End Sub10. Sub cs11. hwnd = dm.GetForegroundWindow()12. TracePrinthwnd13. End Sub复制代码通过上面的归纳,更可以明确多线程基本等同与新建一个内部脚本,可以调用主脚本内的任何子程序资源,调用方式为创建一个该子程序的副本,独立与主程序体之外。如果要在某个多线程内定义一个可以在子程序间传递数据的变量,办法是直接给变量赋值,不要在它调用到的任何子程序中显式或者隐式的定义该变量。如果要实现在程序主体和多线程之间传递数据,需要在程序主体的最前面用DimEnv关键字定义环境变量。具体使用见后面的例子。 (二)多线程命令解释: 1.BeginThread 同时运行过程:可以理解为开辟一块新的内存空间来运行一个任务,在该多线程子程序中所调用的资源,统统纳入这个内存空间,如果需要与外界交换数据,必须通过DimEnv定义的环境变量来实现。为了便于控制每一个线程,调用时可以指定一个变量来保存线程ID,一般把这个变量定义为环境变量,这样可以在主体和线程以及线程之间实现互相控制。 2.PauseThread 暂停线程运行、ContinueThread 继续线程运行、StopThread 停止线程运行:通过线程ID来暂停、继续和停止一个线程,在论坛上看到一位高手用环境变量来实现了这个功能:1. Dimenv 控制2. 3. BeginThread 过程14. 5. 控制 = 暂停6. 7. 控制 = 继续8. 9. 控制 = 停止10. 11. EndScript12. Sub 过程113. 14. While 控制 = 暂停15. Delay 5016. Wend17. If 控制=停止 Then exit Sub18. End Sub复制代码当然需要把这个控制代码插入到多线程子程序的循环体中来执行,也有缺点是必须运行到此处才能实现功能。这是题外话了,灵活的用好暂停、继续功能可以让脚本变得更灵活。比如在控制人物左右行走的子程序中,需要判断障碍物,如果X轴无变化就向上或者向下走,如果X,Y轴都没有变化就判断为卡住,执行卡住处置程序。可以把卡住判断和处置的代码放到一个多线程中,在左右行走子程序开始时打开卡住处置多线程并暂停,在x轴卡住时继续运行卡住处置多线程,实现上下移动并判断y轴值是否变化,如果没有变化就向相反方向走。左右移动的子程序中设置一个按左右行走键并判断x轴无变化就等待的循环,在退出循环时暂停卡住处置多线程。在左右行走的子程序结束的时候关掉卡住处置多线程。这样通过暂停、继续的运用,可以减少频繁的打开关闭多线程。代码如下:1. Dimenv x, y,线程ID2. 3. Sub 左右移动4. 线程ID=BeginThread(障碍物判断)5. PauseThread 线程ID6. While 是否到底目的地=否7. 按左右键行走8. 调用取得人物坐标子程序9. if x轴无变化 then10. ContinueThread 线程ID11. End if12. while x轴无变化13. 按下左右键14. 等待一段时间15. 松开左右键16. 调用取得人物坐标子程序17. Wend18. PauseThread 线程ID19. Wend20. StopThread 线程ID21. End Sub22. Sub 障碍物判断23. while True24. 按上下键行走25. 调用取得人物坐标子程序26. if y轴无变化 then27. 把控制上下的键更换方向28. End if29. wend30. End Sub复制代码 3.GetThreadID 得到当前线程ID:这个从按键自带的例子来看,是在退出线程事件中,用来返回退出的线程ID,从而根据这个ID来确定是哪一个线程退出了,给该线程上绑定的例如大漠、361等插件松绑。这个命令只有在线程结束事件或者线程内部才能返回值,如果忘记在调用时保存线程ID,可以在线程内部使用这个命令获取自身的线程ID。 二、多线程什么情况下应该使用? 多线程使用的时机,大概有两种:一种是单脚本内需要控制开展多项工作,比如上面的例子,在左右行走卡住时开启上下行走和卡住判断;另一种是通过多线程的使用,实现一个脚本对多个游戏窗口的控制,也就是多开,下面就这两种情况说说我的看法。 (一)单脚本单开的多线程这个是否使用多线程得看具体的情况来定,很多时候并不一定需要多线程才能解决问题,可以通过在循环内部插入某些判断代码来确定是否调用别的功能。例如上面的左右行走子程序,可以改成这样:1. Sub 左右移动2. While 是否到底目的地=否3. 按左右键行走4. 调用取得人物坐标子程序5. while x轴无变化6. 按下左右键和上下键7. 等待一段时间8. 松开左右键和上下键9. 调用取得人物坐标子程序10. If y轴无变化 Then11. 把控制上下的键更换方向12. End If13. Wend 14. Wend15. End Sub复制代码 如此通过对控制行走代码的修改,来实现绕过障碍物和卡住判断,无需调用多线程来解决问题。这样无需考虑两个线程之间的按键同步问题和互相干扰的问题,也不要定义多个环境变量来实现数据的交换。像一些比较复杂的脚本,需要同时开展的工作之间没有频繁的数据传递,且确实需要做到实时监控,那么就必须使用多线程了。比如在挂机打怪的时候需要监控草药或者矿产是否出现,一定出现就暂停打怪去采集(假设打怪时间可以暂停),采集完成后继续打怪,可以写出如下代码:1. dimenv 打怪ID,采集ID2. 打怪ID=BeginThread(打怪)3. 采集ID=BeginThread(采集)4. While true5. 6. Wend7. EndScript8. Sub 打怪9. While true10. 打怪11. Wend12. End Sub13. Sub 采集14. While true15. 判断草药是否出现16. if 草药出现 then17. PauseThread 打怪ID18. 采集草药19. ContinueThread 打怪ID20. end If21. Wend 22. End Sub复制代码 当然,在使用多线程时一定要考虑到各种情况的出现,避免在打怪的过程中暂停了打怪线程,导致采集时被怪物攻击的情况,或者采集时草药会集中出现,可以暂缓继续打怪程序,采集完成后继续找草药,确实采集完成再继续打怪,以避免频繁的继续和暂停打怪程序。 (二)单脚本多开的多线程这个需要考虑的问题就更多了,不提倡新手使用多线程,除了多线程不稳定的原因外,对变量作用域不明确、对程序流程的掌握不熟练也是一个原因。单脚本多开,要能够实现对任意线程的完美控制。我曾经想过用一个脚本实现单线程的各个游戏窗口之间的循环控制,这个思路可以用在对多线程的控制上:1.枚举符合要求的窗口句柄;2.把获得的窗口句柄保存在数组h中 ;3.对需要做的每一个后台操作,在指定句柄时,循环到数组h中的每一个成员;1. dim h2. HwndEx = Plugin.Window.Search(记事本)3. h = split(HwndEx, |)4. 5. /假设有一个后台单击命令6. For i=0 to UBound (h)7. Call Plugin.Bkgnd.LeftClick(H(i), x, y)8. Next i复制代码在控制多线程时,需要用到用户自定义界面,把线程ID保存在用户自定义界面的控件上,然后通过按键来实现对各个线程的完美控制。 三、如何实现多线程的灵活控制? 参考:/thread-349064-1-1.html 这个帖子只是说明了多线程控制的思路,具体实现可以这样(还是要抱怨一句:按键的自定义界面不支持控件数组、不能动态添加list列表项,让这件事情变得很难办了): 先按照上图在自定义界面上弄5个文本框(用于手动写入线程标识,可以用角色名等区分,面对自己都搞不清哪个是哪个了)、5个单选按钮(用于保存线程ID和选定线程,如果想同时控制多个线程可以改成用复选框)、3个按钮(名称分别为ButtonPause、ButtonContinue、ButtonStop,用于操作选定线程),然后编写如下脚本:1. DimEnv 线程ID2. Dim i3. i=14. While key 1235. key=GetLastKey6. If key=119 /自己设定的启

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论