ReeKorl

Pause script execution until one of x windows exists, AND pass the window handle to function

9 posts in this topic

Hi all,

I have a script currently working which is used to monitor a piece of software which occasionally pops a messagebox that otherwise would need to be closed off manually. The script works fine for the most part, however I've noticed recently that the program it's monitoring can actually pop one of three different messageboxes I need to close, rather than just the one I was originally looking for.

Currently, the script is as follows (cut down to the vitals for brevity):

Global $i = 0

Do  
    InterfaceRestart()
Until $i = 1

Func InterfaceRestart()
    Local $hWnd1 = WinWait ("[TITLE:Interface; CLASS:#32770]","Window 1 text")
    WinActivate ($hWnd1)
    ControlClick ($hWnd1, "", "[CLASS:Button; INSTANCE:1]", "primary", 1)
End Func

There's some more stuff in there also, mostly pauses to allow these old systems to do something before the script activates the various sections.

Now, I know I need to change the WinWaits to something along the lines of the below to wait for any one of the three windows (sample code is just for two, but can be extended easily enough):

Global $i = 0

Do  
    Do
    ;nothing
    Until WinExists ("[TITLE:Interface; CLASS:#32770]","Window 1 text") OR WinExists ("[TITLE:Interface; CLASS:#32770]","Window 2 text")
    ;Collect window handle here???
    InterfaceRestart($hWnd1)
Until $i = 1

Func InterfaceRestart($hWnd1)
    WinActivate ($hWnd1)
    ControlClick ($hWnd1, "", "[CLASS:Button; INSTANCE:1]", "primary", 1)
End Func

But... I need to know how to do the above AND collect the window handle so it can be passed to the restart function. I blame a lack of sleep, but I've been editing in circles for about an hour now...

Any thoughts? One note about the code - I can't just make it listen for a window based on title and class alone (despite all three being of the same), as there's other ones which could pop with different window text that I absolutely cannot have this click through automatically.

~~R

Share this post


Link to post
Share on other sites



When you like to react on one of the 3 Windows,

WinWaitActive("[TITLE:Interface; CLASS:#32770]","")

will do this job as you expect.

Share this post


Link to post
Share on other sites

I do not know if I got it right, but something like this maybe:

 

Local $hWnd1

While True
    $hWnd1 = WinGetHandle("[TITLE:Interface; CLASS:#32770]")
    If Not @error Then InterfaceRestart($hWnd1)
    Sleep(100)
WEnd

Func InterfaceRestart($hWnd)
    WinActivate ($hWnd)
    ControlClick ($hWnd, "", "[CLASS:Button; INSTANCE:1]", "primary", 1)
End Func

 

Share this post


Link to post
Share on other sites
10 hours ago, AutoBert said:

When you like to react on one of the 3 Windows,

WinWaitActive("[TITLE:Interface; CLASS:#32770]","")

will do this job as you expect.

Unless I'm completely misunderstanding the way that WinWait (and WinWaitActive) work, it won't. I was originally using WinWait (can't use Actiive as I can't guarantee the messagebox will pop focused... don't ask me why, this old program I'm monitoring was written well before my time here) which was working when I thought I was only listening for one particular window, but now I know there's three I need to wait for, hence the move to WinExists with an OR between the definitions. As I understand it, WinWait will completely freeze execution until the window specified exists, so if you try a "WinWait(Win1) OR WinWait(Win2) OR WinWait(Win3)" it will freeze at the point of looking for Win1 (or perhaps not even parse correctly at all). Not what I'm looking for - there could be a number of Win2 or Win3 that appear before Win1 does.

Also, using a single listener with [TITLE:Interface; CLASS:#32770] isn't sufficient, as there's other ones with the same definition that I don't want to close down automatically.

Anyway, that's not the stumbling block I have, what I need is a way to pass the window handle to the restart function, not to detect the window's existence.

10 hours ago, MichaelHB said:

I do not know if I got it right, but something like this maybe:

 

Local $hWnd1

While True
    $hWnd1 = WinGetHandle("[TITLE:Interface; CLASS:#32770]")
    If Not @error Then InterfaceRestart($hWnd1)
    Sleep(100)
WEnd

Func InterfaceRestart($hWnd)
    WinActivate ($hWnd)
    ControlClick ($hWnd, "", "[CLASS:Button; INSTANCE:1]", "primary", 1)
End Func

 

I sort of see what you're getting at, but I don't think I'm going to have any sort of errorlevel to interpret - all messagebox windows are effectively the same, with the only distinction being the text inside them.

On the plus side, I do prefer your looping method of "While True" to the one I'm currently using!

 

Maybe I need to rephrase the question a little... I need to wait for (out of a set of let's say ten possible windows which could appear) one of three specific windows, then pass the handle of which one appeared to another function so it can operate on it.

~~R

Share this post


Link to post
Share on other sites

#5 ·  Posted (edited)

How do you identify the 3 windows ? Michael's example is what you need - just change it a bit to pass every handle to the restart function and inside check if the window is the right one.

Edited by Juvigy
spell check

Share this post


Link to post
Share on other sites

#6 ·  Posted (edited)

The script (when it is just listening for just one specific window) is as below:

Local $hWnd1 = WinWait ("[TITLE:Interface; CLASS:#32770]","Text displayed in window 1")

In simple terms, the list of windows I've found that this pops are as below:

WinExists ("[TITLE:Interface; CLASS:#32770]","Text displayed in window 1") OR_
WinExists ("[TITLE:Interface; CLASS:#32770]","Text displayed in window 2") OR_
WinExists ("[TITLE:Interface; CLASS:#32770]","Text displayed in window 3") OR_

;BUT NOT THESE ONES:

;WinExists ("[TITLE:Interface; CLASS:#32770]","Text displayed in window 4") OR_
;WinExists ("[TITLE:Interface; CLASS:#32770]","Text displayed in window 5")

Line breaks added for legibility. As you can see, they all have the same title and class, but the 'type' of messagebox differs in the text inside them. Technically, the text also differs inside each 'type' but only at the end of the string with UID and timestamp. This is what we need to collect on the ones that need to stay open, and right now it's done manually by an engineer when they check the system. Automating that is something for later though, I need to get this part done so that the 'noise' alerts don't prevent the program itself from running correctly.

I really would prefer not to (for example) pass a list of all windows open through to the closing routine and then detect if it needs to be closed every time it loops. I'm trying to keep this as lightweight as possible, the machines this runs on are very old and slow. Plus, potentially there's going to be tens (or even hundreds) of the ones I don't want closed when one of our engineers looks at it - we don't have anyone monitoring this over the weekend, so the ones we need to keep open may build up whilst nobody's looking.

Is there really no easy way of coding "When any window which matches one of these three definitions exists, tell me what its handle is?"

~~R

Edited by ReeKorl
tidying code

Share this post


Link to post
Share on other sites

Like @Juvigy said, all you need is to change the example to something like this:

Local $hWnd1

While True
    $hWnd1 = WinGetHandle("[TITLE:Interface; CLASS:#32770]","Text displayed in window 1")
    If Not @error Then InterfaceRestart($hWnd1)
    $hWnd1 = WinGetHandle("[TITLE:Interface; CLASS:#32770]","Text displayed in window 2")
    If Not @error Then InterfaceRestart($hWnd1)
    $hWnd1 = WinGetHandle("[TITLE:Interface; CLASS:#32770]","Text displayed in window 3")
    If Not @error Then InterfaceRestart($hWnd1)
    Sleep(100)
WEnd

Func InterfaceRestart($hWnd)
    WinActivate ($hWnd)
    ControlClick ($hWnd, "", "[CLASS:Button; INSTANCE:1]", "primary", 1)
End Func

 

Share this post


Link to post
Share on other sites

Ack... I completely missed that the sample you provided was using WinGetHandle() rather than WinExists()... must be code blindness from staring at it for too long!

Thanks for the assistance (and putting up with my oversights)! I'll give it a test and report back the results - although I'm sure it'll work now I understand what you're all getting at.

~~R

Share this post


Link to post
Share on other sites

Hi all,

Just a quick one to confirm that it's now working exactly as expected from those code snippets suggested. Thanks for the input!

~~R

Share this post


Link to post
Share on other sites

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 account

Sign in

Already have an account? Sign in here.


Sign In Now