smooth 发表于 2022-5-10 20:58:32

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

本帖最后由 smooth 于 2022-5-13 08:19 编辑

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

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

while 1
    sleep(10)
Wend

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


Func OnAutoItExit()
_WinAPI_UnhookWindowsHookEx($hHookMouse)
DllCallbackFree($hCallbackMouse)
EndFunc   ;==>OnAutoItExit


倒计时MsgBox

Func _MsgBoxDJS($flag, $title, $text, $timeout = 10, $Cflag = 1, $hWnd = '')
Global $___Timer = DllCallbackRegister('__Timer', 'int', 'hwnd;uint;uint;dword')
If $timeout = '' Or $timeout = -1 Then $timeout = 10
Global $s__title = $title, $s__text = $text, $__Cflag = $Cflag, $v__zt = 1, $v__ttc = $timeout, $__bttxtFlag = 0
Global $__Timer_DLL = DllCall('user32.dll', 'uint', 'SetTimer', 'hwnd', 0, 'uint', 0, 'int', 100, 'ptr', DllCallbackGetPtr($___Timer))
If $Cflag = 0 Then
If StringRegExp($title, '%s') = 0 Then
   $title = '%s' & $title
   $s__title = $title
EndIf
$title = StringRegExpReplace($title, '%s', StringFormat('%02s', $v__ttc))
$title = StringRegExpReplace($title, '%\\s', '%s')
ElseIf $Cflag = 1 Then
If Not StringRegExp($text, '%s') Then
   $text = '%s' & $text
   $s__text = $text
EndIf
$text = StringRegExpReplace($text, '%s', StringFormat('%02s', $v__ttc))
$text = StringRegExpReplace($text, '%\\s', '%s')
EndIf
Local $rtMsg = MsgBox($flag, $title, $text, 0, $hWnd)
DllClose($__Timer_DLL)
DllCallbackFree($___Timer)
Return $rtMsg
EndFunc   ;==>_MsgBoxDJS
Func __Timer($hWnd, $uiMsg, $idEvent, $dwTime)
Global $__Timer_DLL, $__bttxtFlag, $__Cflag, $s__title, $v__ttc, $s__text, $v__zt, $___Timer, $s_titleF, $v__TimerJS
If $idEvent = $__Timer_DLL Then
Global $s__bttxt, $i_ControlFocus, $n__Static
If $__bttxtFlag = 0 Then
   WinActivate($s__title)
   If $__Cflag = 0 Then
    $s_titleF = StringRegExpReplace($s__title, '%s', StringFormat('%02s', $v__ttc))
    $s_titleF = StringRegExpReplace($s_titleF, '%\\s', '%s')
    $i_ControlFocus = ControlGetFocus($s_titleF)
   EndIf
   If $__Cflag = 1 Or $__Cflag = 2 Then $i_ControlFocus = ControlGetFocus($s__title)
   $s__bttxt = ControlGetText($s__title, $s__text, $i_ControlFocus)
   If $__Cflag = 1 Then
    $n__Static = 'Static1'
    Local $sTxt = ControlGetText($s__title, StringRegExpReplace($s__text, '%s', StringFormat('%02s', $v__ttc)), 'Static1')
    If Not $sTxt Or @error Then $n__Static = 'Static2'
   EndIf
   $__bttxtFlag = 1
EndIf
If $v__TimerJS = 9 Then
   If $__Cflag = 0 Then
    $_title1 = StringRegExpReplace($s__title, '%s', StringFormat('%02s', $v__ttc - $v__zt + 1))
    $_title1 = StringRegExpReplace($_title1, '%\\s', '%s')
    $_title2 = StringRegExpReplace($s__title, '%s', StringFormat('%02s', $v__ttc - $v__zt))
    $_title2 = StringRegExpReplace($_title2, '%\\s', '%s')
    WinSetTitle($_title1, $s__text, $_title2)
   ElseIf $__Cflag = 1 Then
    $_text1 = StringRegExpReplace($s__text, '%s', StringFormat('%02s', $v__ttc - $v__zt + 1))
    $_text1 = StringRegExpReplace($_text1, '%\\s', '%s')
    $_text2 = StringRegExpReplace($s__text, '%s', StringFormat('%02s', $v__ttc - $v__zt))
    $_text2 = StringRegExpReplace($_text2, '%\\s', '%s')
    ControlSetText($s__title, $_text1, $n__Static, $_text2)
   ElseIf $__Cflag = 2 Then
    ControlSetText($s__title, $s__text, $i_ControlFocus, $s__bttxt & StringFormat(' %02s', $v__ttc - $v__zt))
   EndIf
   If $v__zt = $v__ttc Then
    If $__Cflag = 0 Then $s__title = $_title2
    If $__Cflag = 1 Then $s__text = $_text2
    DllClose($__Timer_DLL)
;~   DllCallbackFree($___Timer)
    ControlClick($s__title, $s__text, $i_ControlFocus, '', 2)
   EndIf
   $v__zt += 1
   $v__TimerJS = 0
Else
   $v__TimerJS += 1
EndIf
EndIf
EndFunc   ;==>__Timer

tubaba 发表于 2022-5-11 12:18:19

简单的方法,在弹窗前先_WinAPI_UnhookWindowsHookEx,弹好后再重新注册

tubaba 发表于 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)
;~         DllClose($__Timer_DLL)
      DllCallbackFree($___Timer)

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

仅供参考

smooth 发表于 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、注册了鼠标钩子,鼠标像是被什么东西拽住了一样,有什么方法能优化呢?

tubaba 发表于 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)
;~         DllClose($__Timer_DLL)
      DllCallbackFree($___Timer)

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

smooth 发表于 2022-5-17 16:03:21

tubaba 发表于 2022-5-13 16:31
我觉得吧,不到万不得已不要用全局lowlevel鼠标钩子,虽然全局钩子可能有性能上的损失,但是不会像你写的那 ...

不好意思,现在才回复,按照你的提示进行了修改,果然弹出Msgbox的时候,已经不再卡顿了,谢谢大佬!
页: [1]
查看完整版本: [已解决]全局鼠标钩子与倒计时Msgbox有冲突