Tag Archives: StructureChangedEvent

Daily automation: recording user’s actions


Applications are not stones. They’re changing during the user’s session. About which sort of changes am I talking? There might be several sorts of them:

  • the application structure changed (a new control appeared or an existing’s gone)
  • a control’s property changed
  • an event invoked (user clicked a control, for the easiest example)
  • a new child window appeared
  • the main window is closed

Today we discuss the case  of a control’s adding occurrence.

Task: demonstrate how to initiate the structure changed via an application’s menu item and how the change can be recorded.

Requirements: use the UIAutomation to use an event handler.

Solution: we are going to write events we collected to a log file and, for our information, to a message box:

Set-StrictMode -Version Latest;
ipmo [path]\UIAutomation.dll;</pre>
# start the process and atach event handlers to the window
Start-Process notepad -PassThru | `
 Get-UIAWindow | `
 Register-UIAStructureChangedEvent -ChildAdded `
 -EventAction `
 { # write to a file
 param($src, $e)
 # report everything
 "'$($src.Current.Name)' has gotten a child" >> "$env:Temp\sample_report.txt";
 if ($src.Current.Name.Length -eq 0) {
 "===================================" >> "$env:Temp\sample_report.txt";
 "Oh, this is what we are waiting for!" >> "$env:Temp\sample_report.txt";
 "AutomaitonId = $($src.Current.AutomaitonId)" >> "$env:Temp\sample_report.txt";
 "ControlType = $($src.Current.ControlType.ProgrammaticName)" >> "$env:Temp\sample_report.txt";
 "ClassName = $($src.Current.ClassName)" >> "$env:Temp\sample_report.txt";
 "-----------------------------------" >> "$env:Temp\sample_report.txt";
 }
 },
 { # display a message box
 param($src, $e)
 # report only what happened under the menu item hierarchy
 if ($src.Current.ControlType.ProgrammaticName -eq 'ControlType.StatusBar') {
 [System.Windows.Forms.MessageBox]::Show($src.Current.Name + "`t" + `
 $src.Current.AutomationId + "`r`n" + `
 $e + "`r`n" + `
 $src.Current.ControlType.ProgrammaticName);
 }
 };

# depending on was or wasn't the Status Bar shown on
# the status bar will or won't be shown
# and the event handlers we linked to the window will fire
Get-UIAMenuItem -Name View | Invoke-UIAMenuItemExpand | Get-UIAMenuItem -Name 'Status Bar' | Invoke-UIAMenuItemClick;
Get-UIAMenuItem -Name View | Invoke-UIAMenuItemExpand | Get-UIAMenuItem -Name 'Status Bar' | Invoke-UIAMenuItemClick;
Get-UIAMenuItem -Name View | Invoke-UIAMenuItemExpand | Get-UIAMenuItem -Name 'Status Bar' | Invoke-UIAMenuItemClick;
Get-UIAMenuItem -Name View | Invoke-UIAMenuItemExpand | Get-UIAMenuItem -Name 'Status Bar' | Invoke-UIAMenuItemClick;
<pre>

After the code is processed by PowerShell, the log file in our user’s TEMP folder contains the information we’ve collected.

(MS) UIAutomation: how to be informed if a control disappears…


An interesting question has been raised yesterday: how UIAutomation help to deal with a control that is disappearing. As known, MS UIAutomation works with only controls that are visible. It’s either ideology and technical limitation.
How the button I mentioned can disappear? For example, this is a button serving a progress bar of a wizard with the label Stop on its face. The progress bar achieves 100% and the button hides.

Using such an awkward code is not a solution:

while (Get-UIAWindow -p processname | Get-UIAButton -n Stop)

Here comes the help again from MS UI Automation: StructureChangedEvent provides us with six types of EventID, among others is the one we needed – ChildRemoved.

Task: wait for a button to be out of sight.

Requirements: get a signal from the button that can triger the main code. Use StructureChangedEventHandler.

Solution: the following sample represents the use of StructureChangedEvent

ipmo .\UIAutomation.dll
[bool]$global:buttonVisible1 = $true;
[bool]$global:buttonVisible2 = $true;
[bool]$global:buttonAddedAgain = $false;
Get-UIAWindow -n ShowHideButton | Get-UIAButton -n Button | Register-UIAStructureChangedEvent -ChildRemoved -EventAction {"01" >> c:\report.txt; $global:buttonVisible1=$false; "1" >> c:\report.txt;} -Verbose
Get-UIAWindow -n ShowHideButton | Get-UIAButton -n Button | Register-UIAStructureChangedEvent -ChildRemoved -EventAction {"02" >> c:\report.txt; $global:buttonVisible2=$false; "2" >> c:\report.txt;} -Verbose
Get-UIAWindow -n ShowHideButton | Register-UIAStructureChangedEvent -ChildAdded -EventAction {$global:buttonAddedAgain=$true; "3" >> c:\report.txt;} -Verbose
#sleep -Seconds 5
#Write-Host "1" $global:buttonVisible1
#Write-Host "2" $global:buttonVisible2
#Write-Host "3" $global:buttonAddedAgain

while ($global:buttonVisible1 -eq $true -and $global:buttonVisible2 -eq $true){
	sleep -Seconds 1;
	Write-Host "1" $global:buttonVisible1
	Write-Host "2" $global:buttonVisible2
	Write-Host "waiting...";
}
Write-Host "completed";
Write-Host "1" $global:buttonVisible1
Write-Host "2" $global:buttonVisible2
Write-Host "3" $global:buttonAddedAgain

The sample works with a simple program that is a form with two buttons. One button is Show/Hide button, its click event shows/hides the second button.

Just run the program (samples 0.6.2 or newer), after that run the script (it subscribes to events) and click one or several times upon the Show/Hide button.
Soon or later you’ll see both global variables set to $false, and the third to $true.

Restrictions may apply, to read more about the event and which eventId can be used on a purpose, visit StructureChangedEventArgs Constructor

%d bloggers like this: