找回密码  加入

AUTOIT CN

搜索
查看: 211|回复: 5

[AU3基础] [已解决]全局鼠标钩子与倒计时Msgbox有冲突

[复制链接]
发表于 2022-5-10 20:58:32 | 显示全部楼层 |阅读模式
本帖最后由 smooth 于 2022-5-13 08:19 编辑

设置全局鼠标钩子,并启用倒计时版的Msgbox,发现只要弹出Msgbox,很快鼠标钩子就丢失了,获取不到鼠标点击了,把倒计时的Msgbox改为普通的Msgbox后没有问题。
倒计时Msgbox的自定义函数里面,设置了回调函数,调用了SetTimer这个函数,看不出来冲突的地方,有大佬知道的,麻烦指点一二,谢谢!

  1. ;设置全局鼠标钩子
  2. Global $hCallbackMouse = DllCallbackRegister("LowLevelMouseProc", "long", "int;wparam;lparam")
  3. Global $hModule = _WinAPI_GetModuleHandle(0)
  4. Global $hHookMouse = _WinAPI_SetWindowsHookEx($WH_MOUSE_LL, DllCallbackGetPtr($hCallbackMouse), $hModule)
  5. Global $bMouseClick = False
  6. OnAutoItExitRegister("OnAutoItExit")

  7. while 1
  8.     sleep(10)
  9. Wend

  10. Func LowLevelMouseProc($nCode, $wParam, $lParam)
  11. If $nCode < 0 Then Return _WinAPI_CallNextHookEx($hHookMouse, $nCode, $wParam, $lParam)
  12. If $wParam = $WM_LBUTTONDOWN Then ;按下鼠标左键
  13. ;~   ToolTip('X:' & MouseGetPos(0) & ',Y:' & MouseGetPos(1), 0, 0)
  14.   $bMouseClick = True
  15. EndIf
  16. Return _WinAPI_CallNextHookEx(0, $nCode, $wParam, $lParam)
  17. EndFunc   ;==>LowLevelMouseProc


  18. Func OnAutoItExit()
  19. _WinAPI_UnhookWindowsHookEx($hHookMouse)
  20. DllCallbackFree($hCallbackMouse)
  21. EndFunc   ;==>OnAutoItExit
复制代码


倒计时MsgBox

  1. Func _MsgBoxDJS($flag, $title, $text, $timeout = 10, $Cflag = 1, $hWnd = '')
  2. Global $___Timer = DllCallbackRegister('__Timer', 'int', 'hwnd;uint;uint;dword')
  3. If $timeout = '' Or $timeout = -1 Then $timeout = 10
  4. Global $s__title = $title, $s__text = $text, $__Cflag = $Cflag, $v__zt = 1, $v__ttc = $timeout, $__bttxtFlag = 0
  5. Global $__Timer_DLL = DllCall('user32.dll', 'uint', 'SetTimer', 'hwnd', 0, 'uint', 0, 'int', 100, 'ptr', DllCallbackGetPtr($___Timer))
  6. If $Cflag = 0 Then
  7.   If StringRegExp($title, '%s') = 0 Then
  8.    $title = '%s' & $title
  9.    $s__title = $title
  10.   EndIf
  11.   $title = StringRegExpReplace($title, '%s', StringFormat('%02s', $v__ttc))
  12.   $title = StringRegExpReplace($title, '%\\s', '%s')
  13. ElseIf $Cflag = 1 Then
  14.   If Not StringRegExp($text, '%s') Then
  15.    $text = '%s' & $text
  16.    $s__text = $text
  17.   EndIf
  18.   $text = StringRegExpReplace($text, '%s', StringFormat('%02s', $v__ttc))
  19.   $text = StringRegExpReplace($text, '%\\s', '%s')
  20. EndIf
  21. Local $rtMsg = MsgBox($flag, $title, $text, 0, $hWnd)
  22. DllClose($__Timer_DLL)
  23. DllCallbackFree($___Timer)
  24. Return $rtMsg
  25. EndFunc   ;==>_MsgBoxDJS
  26. Func __Timer($hWnd, $uiMsg, $idEvent, $dwTime)
  27. Global $__Timer_DLL, $__bttxtFlag, $__Cflag, $s__title, $v__ttc, $s__text, $v__zt, $___Timer, $s_titleF, $v__TimerJS
  28. If $idEvent = $__Timer_DLL[0] Then
  29.   Global $s__bttxt, $i_ControlFocus, $n__Static
  30.   If $__bttxtFlag = 0 Then
  31.    WinActivate($s__title)
  32.    If $__Cflag = 0 Then
  33.     $s_titleF = StringRegExpReplace($s__title, '%s', StringFormat('%02s', $v__ttc))
  34.     $s_titleF = StringRegExpReplace($s_titleF, '%\\s', '%s')
  35.     $i_ControlFocus = ControlGetFocus($s_titleF)
  36.    EndIf
  37.    If $__Cflag = 1 Or $__Cflag = 2 Then $i_ControlFocus = ControlGetFocus($s__title)
  38.    $s__bttxt = ControlGetText($s__title, $s__text, $i_ControlFocus)
  39.    If $__Cflag = 1 Then
  40.     $n__Static = 'Static1'
  41.     Local $sTxt = ControlGetText($s__title, StringRegExpReplace($s__text, '%s', StringFormat('%02s', $v__ttc)), 'Static1')
  42.     If Not $sTxt Or @error Then $n__Static = 'Static2'
  43.    EndIf
  44.    $__bttxtFlag = 1
  45.   EndIf
  46.   If $v__TimerJS = 9 Then
  47.    If $__Cflag = 0 Then
  48.     $_title1 = StringRegExpReplace($s__title, '%s', StringFormat('%02s', $v__ttc - $v__zt + 1))
  49.     $_title1 = StringRegExpReplace($_title1, '%\\s', '%s')
  50.     $_title2 = StringRegExpReplace($s__title, '%s', StringFormat('%02s', $v__ttc - $v__zt))
  51.     $_title2 = StringRegExpReplace($_title2, '%\\s', '%s')
  52.     WinSetTitle($_title1, $s__text, $_title2)
  53.    ElseIf $__Cflag = 1 Then
  54.     $_text1 = StringRegExpReplace($s__text, '%s', StringFormat('%02s', $v__ttc - $v__zt + 1))
  55.     $_text1 = StringRegExpReplace($_text1, '%\\s', '%s')
  56.     $_text2 = StringRegExpReplace($s__text, '%s', StringFormat('%02s', $v__ttc - $v__zt))
  57.     $_text2 = StringRegExpReplace($_text2, '%\\s', '%s')
  58.     ControlSetText($s__title, $_text1, $n__Static, $_text2)
  59.    ElseIf $__Cflag = 2 Then
  60.     ControlSetText($s__title, $s__text, $i_ControlFocus, $s__bttxt & StringFormat(' %02s', $v__ttc - $v__zt))
  61.    EndIf
  62.    If $v__zt = $v__ttc Then
  63.     If $__Cflag = 0 Then $s__title = $_title2
  64.     If $__Cflag = 1 Then $s__text = $_text2
  65.     DllClose($__Timer_DLL)
  66. ;~     DllCallbackFree($___Timer)
  67.     ControlClick($s__title, $s__text, $i_ControlFocus, '', 2)
  68.    EndIf
  69.    $v__zt += 1
  70.    $v__TimerJS = 0
  71.   Else
  72.    $v__TimerJS += 1
  73.   EndIf
  74. EndIf
  75. EndFunc   ;==>__Timer
复制代码

发表于 2022-5-11 12:18:19 | 显示全部楼层
简单的方法,在弹窗前先_WinAPI_UnhookWindowsHookEx,弹好后再重新注册
发表于 2022-5-11 12:29:07 | 显示全部楼层
本帖最后由 tubaba 于 2022-5-11 13:22 编辑

Global $__Timer_DLL = DllCall('user32.dll', 'uint', 'SetTimer', 'hwnd', 0, 'uint', 0, 'int', 100, 'ptr', DllCallbackGetPtr($___Timer))

DllClose($__Timer_DLL)           ?????可能只是可以忽略的错误,其它看不出什么问题,。
测试一下可能是每0.1秒调用_Timer一次,逢十进一,同时又hook鼠标,这个频率是不是太高了,造成卡死。

试试把调用的频率改为1秒1次,毕竟不需要那么精确,当然函数要修改一下。


或者就是我上面说的

_WinAPI_UnhookWindowsHookEx($hHookMouse)
Local $rtMsg = MsgBox($flag, $title, $text, 0, $hwnd)
        If IsArray($__Timer_DLL) Then DllCall('user32.dll', 'bool', 'KillTimer', 'hwnd', 0, 'uint_ptr', $__Timer_DLL[0])
;~         DllClose($__Timer_DLL)
        DllCallbackFree($___Timer)

$hHookMouse = _WinAPI_SetWindowsHookEx($WH_MOUSE_LL, DllCallbackGetPtr($hCallbackMouse), $hModule)

仅供参考
 楼主| 发表于 2022-5-12 17:01:48 | 显示全部楼层
tubaba 发表于 2022-5-11 12:29
Global $__Timer_DLL = DllCall('user32.dll', 'uint', 'SetTimer', 'hwnd', 0, 'uint', 0, 'int', 100, 'p ...

谢谢大佬,测试可行。但是还有两个小问题,请教一下。
1、就是鼠标钩子在脚本运行的过程中,有时候会莫名其妙的丢失掉,注册后能否在while里面检测它在不在,如果不在就重新注册?我没有找到检测钩子的方法;如果不检测,在while里面不停的注册,感觉更卡顿了。
2、注册了鼠标钩子,鼠标像是被什么东西拽住了一样,有什么方法能优化呢?
发表于 2022-5-13 16:31:04 | 显示全部楼层
本帖最后由 tubaba 于 2022-5-13 16:42 编辑

我觉得吧,不到万不得已不要用全局lowlevel鼠标钩子,虽然全局钩子可能有性能上的损失,但是不会像你写的那么夸张,也许你的代码需要好好优化一下,只在需要钩的时候注册,一旦任务完成,应该卸载,等 到下一次需要调用的时候再重新注册.


_WinAPI_UnhookWindowsHookEx($hHookMouse);这句应放在settimer之前,可能会好些.
Global $__Timer_DLL = DllCall('user32.dll', 'uint', 'SetTimer', 'hwnd', 0, 'uint', 0, 'int', 100, 'ptr', DllCallbackGetPtr($___Timer))
.....
.....
Local $rtMsg = MsgBox($flag, $title, $text, 0, $hwnd)
        If IsArray($__Timer_DLL) Then DllCall('user32.dll', 'bool', 'KillTimer', 'hwnd', 0, 'uint_ptr', $__Timer_DLL[0])
;~         DllClose($__Timer_DLL)
        DllCallbackFree($___Timer)

$hHookMouse = _WinAPI_SetWindowsHookEx($WH_MOUSE_LL, DllCallbackGetPtr($hCallbackMouse), $hModule)
 楼主| 发表于 7 天前 | 显示全部楼层
tubaba 发表于 2022-5-13 16:31
我觉得吧,不到万不得已不要用全局lowlevel鼠标钩子,虽然全局钩子可能有性能上的损失,但是不会像你写的那 ...

不好意思,现在才回复,按照你的提示进行了修改,果然弹出Msgbox的时候,已经不再卡顿了,谢谢大佬!
您需要登录后才可以回帖 登录 | 加入

本版积分规则

QQ|小黑屋|手机版|AUTOIT CN ( 鲁ICP备19019924号-1 )谷歌 百度

GMT+8, 2022-5-24 08:21 , Processed in 0.171875 second(s), 28 queries .

Powered by Discuz! X3.4 Licensed

© 2001-2017 Comsenz Inc.

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