AUTOlTER Posted February 8, 2023 Share Posted February 8, 2023 Hi I wonder if it's possible to interrupt my script when a specific window closes. This is similar to GUISetOnEvent() but the window I'm using is not created by GUICreate(), it's just a window app. My script checks with some frecuency whether the window still exists. However, this is racy since this event is asynchronic w.r.t my script. When it happens, my script end up clicking any other window behind. Options to consider are - Always use ControlClick to prevent clicks outside this window. - With a timer, poll the existence of the window. Still racy but less probable to happen. (efficiency is not required) - Get interrupted whenever the window dissapears. (What I'm looking for) Actually, I use MouseClick with client coords. Thanks in advance Link to comment Share on other sites More sharing options...
Nine Posted February 8, 2023 Share Posted February 8, 2023 Consider using AdlibRegister to check if the window still exists, if not exit your script. “They did not know it was impossible, so they did it” ― Mark Twain Spoiler Block all input without UAC Save/Retrieve Images to/from Text Monitor Management (VCP commands) Tool to search in text (au3) files Date Range Picker Virtual Desktop Manager Sudoku Game 2020 Overlapped Named Pipe IPC HotString 2.0 - Hot keys with string x64 Bitwise Operations Multi-keyboards HotKeySet Recursive Array Display Fast and simple WCD IPC Multiple Folders Selector Printer Manager GIF Animation (cached) Screen Scraping Multi-Threading Made Easy Link to comment Share on other sites More sharing options...
mistersquirrle Posted February 9, 2023 Share Posted February 9, 2023 (edited) What you want is something along the lines of DllCallbackRegister + _WinAPI_SetWinEventHook. If set up correctly this will interrupt your script. I have a small example from a script that I've used it in previously, but it's not something that I use very often so I don't know a lot about it. I didn't change the code that was in my script to fit your needs, I'll leave that up to you. You will need to look up a couple resources to understand it more: https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setwineventhook https://learn.microsoft.com/en-us/windows/win32/winauto/event-constants expandcollapse popup#include <WinAPI.au3> #include <WinAPISys.au3> Local $hEventProc = DllCallbackRegister('_EventProc', "none", "ptr;dword;hwnd;long;long;dword;dword") Local $hEventHook = _WinAPI_SetWinEventHook($EVENT_MIN, $EVENT_MAX, DllCallbackGetPtr($hEventProc)) OnAutoItExitRegister('__Exit') While 1 Sleep(100) WEnd Func _EventProc($hEventHook, $iEvent, $hWnd, $iObjectID, $iChildID, $iThreadId, $iEventTime) #forceref $hEventHook, $iObjectID, $iChildID, $iThreadId, $iEventTime ; https://learn.microsoft.com/en-us/windows/win32/winauto/event-constants Local $hCurrHnd Local $hTimer = TimerInit() ;~ ConsoleWrite('Event: ' & Hex($iEvent, 8) & @CRLF) ; Don't recommend that you enable this, you'll be spammed with logs Switch $iEvent Case $EVENT_SYSTEM_MOVESIZEEND $hCurrHnd = WinGetHandle('[ACTIVE]') While _WinAPI_GetParent($hWnd) <> 0 $hWnd = _WinAPI_GetParent($hWnd) WEnd If $hCurrHnd <> $hWnd Then Return $iEvent ConsoleWrite(WinGetTitle($hWnd) & " - MoveEventEnd, " & Round(TimerDiff($hTimer), 2) & 'ms' & @CRLF) ;~ Case $EVENT_SYSTEM_MOVESIZESTART ;~ $hCurrHnd = __WinHandle() ;~ While _WinAPI_GetParent($hWnd) <> 0 ;~ $hWnd = _WinAPI_GetParent($hWnd) ;~ WEnd ;~ If $hCurrHnd <> $hWnd Then Return False ;~ ConsoleWrite(WinGetTitle($hWnd) & " - Start" & @CRLF) Case $EVENT_OBJECT_LOCATIONCHANGE $hCurrHnd = WinGetHandle('[ACTIVE]') While _WinAPI_GetParent($hWnd) <> 0 $hWnd = _WinAPI_GetParent($hWnd) WEnd If $hCurrHnd <> $hWnd Then Return $iEvent ConsoleWrite("$EVENT_OBJECT_LOCATIONCHANGE - " & Round(TimerDiff($hTimer), 2) & 'ms' & @CRLF) Case $EVENT_OBJECT_NAMECHANGE $hCurrHnd = WinGetHandle('[ACTIVE]') While _WinAPI_GetParent($hWnd) <> 0 $hWnd = _WinAPI_GetParent($hWnd) WEnd If $hCurrHnd <> $hWnd Then Return $iEvent ConsoleWrite("$EVENT_OBJECT_NAMECHANGE - " & Round(TimerDiff($hTimer), 2) & 'ms' & @CRLF) EndSwitch EndFunc ;==>_EventProc Func __Exit() _WinAPI_UnhookWinEvent($hEventHook) DllCallbackFree($hEventProc) Exit EndFunc ;==>__Exit What you would want to do is likely have a function that wraps your MouseClick, and have a variable that you can toggle on/off if the window exists, or not. That way you can toggle the variable to false if the window is destroyed, and that can either exit your loop/function that's doing the clicks. Even if it's not at the point of checking that then having your MouseClick wrapped in a function that checks if the variable is true before clicking should keep you from clicking when the window doesn't exist. Something like Local $bClick = False Func _MouseClick($sButton = 'main', $iX = Default, $iY = Default, $iClicks = 1, $iSpeed = 10) If $bClick = True Then Return MouseClick($sButton, $iX, $iY, $iClicks, $iSpeed) EndFunc ;==>_MouseClick The other much more simple option is to use the _MouseClick function like above and replace the If check with If WinExists('YourWindow'), not very efficient but should take care of clicking when the window doesn't exist, for the most part (since it could still happen in a tiny time between the check and click function). ControlClick if it works for your window will be safer. Edited February 9, 2023 by mistersquirrle We ought not to misbehave, but we should look as though we could. Link to comment Share on other sites More sharing options...
Nine Posted February 9, 2023 Share Posted February 9, 2023 If you prefer using a hook then I would recommend using _WinAPI_RegisterShellHookWindow as it is more appropriate when a window closes. Here an example : #include <APISysConstants.au3> #include <WinAPISysWin.au3> #include <Constants.au3> If WinExists("[CLASS:Notepad]") Then Exit MsgBox($MB_SYSTEMMODAL, "Error", "Close all instance of Notepad") Run("Notepad") Global $hTarget = WinWait("[CLASS:Notepad]") OnAutoItExitRegister(OnAutoItExit) Global $hForm = GUICreate('') GUIRegisterMsg(_WinAPI_RegisterWindowMessage('SHELLHOOK'), WM_SHELLHOOK) _WinAPI_RegisterShellHookWindow($hForm) While 1 Sleep(100) WEnd Func WM_SHELLHOOK($hWnd, $iMsg, $wParam, $lParam) If $lParam <> $hTarget Then Return Switch $wParam Case $HSHELL_WINDOWDESTROYED ConsoleWrite("Notepad has been closed" & @CRLF) Exit EndSwitch EndFunc ;==>WM_SHELLHOOK Func OnAutoItExit() _WinAPI_DeregisterShellHookWindow($hForm) EndFunc ;==>OnAutoItExit The script will stop when you close Notepad... mistersquirrle and spudw2k 2 “They did not know it was impossible, so they did it” ― Mark Twain Spoiler Block all input without UAC Save/Retrieve Images to/from Text Monitor Management (VCP commands) Tool to search in text (au3) files Date Range Picker Virtual Desktop Manager Sudoku Game 2020 Overlapped Named Pipe IPC HotString 2.0 - Hot keys with string x64 Bitwise Operations Multi-keyboards HotKeySet Recursive Array Display Fast and simple WCD IPC Multiple Folders Selector Printer Manager GIF Animation (cached) Screen Scraping Multi-Threading Made Easy Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now