How does Wait-UiaNoWindow work?

Jul 17, 2014 at 7:08 AM
Edited Jul 17, 2014 at 7:10 AM

I can't understand the logic of Wait-UiaNoWindow cmdlet — should it wait until an existing window closes? Please provide some details on this cmdlet with usage examples.

My task is:
  • To pause script execution until a specific window appears. I do it this way:
While ((Wait-UiaWindow -Name 'Calculator' -Seconds 0) -eq $False) {Out-Null}
  • Then continue execution until the same window closes. I tried to do it this the same way with Wait-UiaNoWindow cmdlet, but it does not work as I expect:
While ((Wait-UiaNoWindow -Name 'Calculator' -Seconds 0) -eq $False) {Out-Null}
Please correct me if I'm wrong or is there another solution?
Jul 17, 2014 at 8:29 AM
Edited Jul 17, 2014 at 8:40 AM
HI ymarushchenko,
it seems to me that the Wait-UiaNoWindow cmdlet that is based on Get-UiaWindow cmdlet needs re-thinking. It's rarely used and I'll review its meaning soon.

Regarding your task, for the first part the easiest way is to take the Get-UiaWindow/Wait-UiaWindow cmdlet (the former returns object or throw exception, the latter returns true/false).
For example:
Get-UiaWindow -n *calc* -Seconds 300
Wait-UiaWindow -Name *calc* -sec 3600
These cmdlets use smart enough sleeping algorithm aiming not to overload your system with Automation queries. In practice, this means that the longer waiting time (the -Seconds parameter) you use, the rarer the cmdlet queries for a window. You could see how often it queries in the log (by default, it is here $env:USERPROFILE\Documents\Uia.log):

[2014-07-17 11:01:27.1603] [INFO] Get-UiaWindow -Win32 $false -Name calc -First $false -Recurse $false -Timeout 300000 -Seconds 300 -IsCritical $false -Highlight $true -HighlightParent $true
[2014-07-17 11:01:27.2123] [INFO] OnSleepHook()
[2014-07-17 11:01:30.2647] [INFO] OnSleepHook()
[2014-07-17 11:01:56.8714] [INFO] Wait-UiaWindow -Win32 $false -Name calc -First $false -Recurse $false -Timeout 3600000 -Seconds 3600 -IsCritical $false -Highlight $true -HighlightParent $true
[2014-07-17 11:01:56.9674] [INFO] OnSleepHook()
[2014-07-17 11:02:15.1038] [INFO] OnSleepHook()

If you choose long enough time interval, the cmdlet will get the window in several seconds after it appeared.

There is also another way to approach this task - you can get the appropriate event:
Get-UiaDesktop | Register-UiaWindowOpenedEvent -EventAction { param($src, $e) [System.Windows.Forms.MessageBox]::Show("window has opened: " + $src.Current.Name); }
However, the code that you can you in scripblock is limited (it's on another thread), you could see from the code only global variables, you can't work with console like via the Write-Host cmdlet. It could also be late for several seconds. Sometimes, MS UI Automation doubles events...

Anyway, both ways are working are are widely used in my tests (the first way is used much more often).

Now, the second part:
Get-UiaWindow -n *calc* -sec 300 | Register-UiaWindowClosedEvent -EventAction { param($src, $e) [System.Windows.Forms.MessageBox]::Show("window has been closed: " + $src.Current.Name); }
You need to pass the window to the Register-UiaWindowClosedEvent cmdlet because this event fires from the window itself. Moreover, the Current set of properties would not work as the window is gone. You coul use, probably, $src.Cached.
If you need just to be signaled about the event, it could be enough.

Jul 17, 2014 at 8:53 AM
The Wait-UiaNoWindow cmdlet works in the following manner: it waits for the time you have chosen in the -Seconds parameter (by default, 5 seconds). If all the time of waiting there was no window the supplied parameters expected, it returns false.
If a window has appeared during the work of the cmdlet, it returns true.
Now, it seems to me odd (it's just as the Wait-UiaWindow cmdlet works).

For example,
Wait-UiaWindow -Name *calc* -Seconds 30
If no calc.exe was running, it returns $false.

Hmm, there's a need to make it another way.

You could try for the second part of your task the following:
Wait-UiaWindow -n *your*window* -Seconds NNN
# close the window
if( -not (Wait-UiaNoWindow -n *your window* -sec [the time window needs to be properly closed])) { "that's okay"; }