[已解决]全局鼠标钩子与倒计时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
简单的方法,在弹窗前先_WinAPI_UnhookWindowsHookEx,弹好后再重新注册 本帖最后由 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)
仅供参考
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: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)
tubaba 发表于 2022-5-13 16:31
我觉得吧,不到万不得已不要用全局lowlevel鼠标钩子,虽然全局钩子可能有性能上的损失,但是不会像你写的那 ...
不好意思,现在才回复,按照你的提示进行了修改,果然弹出Msgbox的时候,已经不再卡顿了,谢谢大佬!
页:
[1]