2

I'm trying to click on paint's save button, but it's not recognizing the window controls. Am I doing something wrong? For example this code only recognizes the title of the window, but does not recognize the controls of that window.

Can anyone help?

Add-Type -AssemblyName System.Drawing
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName UIAutomationClient
Add-Type -AssemblyName UIAutomationTypes
Add-Type -AssemblyName System.Xml.Linq

$nameProcess = "mspaint"
$windowTitle = "Untitled"


$processes = [System.Diagnostics.Process]::GetProcessesByName($nameProcess)

foreach ($process in $processes) {
    if ($process.MainWindowTitle.Contains($windowTitle)) {
        if ($process -ne $null) {
            $root = [System.Windows.Automation.AutomationElement]::FromHandle($process.MainWindowHandle)
            $elements = $root.FindAll([System.Windows.Automation.TreeScope]::Subtree, [System.Windows.Automation.Condition]::TrueCondition) | Select-Object -Unique
            
            foreach ($item in $elements) {           
                if ($item -ne $null) {                 
                    $pattern = $null
                    if ($item.TryGetCurrentPattern([System.Windows.Automation.InvokePattern]::Pattern, [ref]$pattern)) {
                        write-host $item.Current.Name -ForegroundColor Green
                        if ($item.Current.Name -eq "Save") {
                            $pattern.Invoke()
                        }
                    }
                }
            }
        }
    }
}
zett42
  • 25,437
  • 3
  • 35
  • 72
megaultron
  • 399
  • 2
  • 15
  • `Select-Object -Unique` doesn't work here. If I remove that, it still only lists the window control buttons like "Minimize" and "Maximize". The cause could be that `System.Windows.Automation` uses UIA2 interfaces only, which either don't work or are not reliable when working with some newer applications. The newer UIA3 interfaces unfortunately don't have a .NET counterpart, which make them harder to use. There are 3rd party libraries like FlaUI that provide UIA3 wrappers. See [this answer](https://stackoverflow.com/a/73541499/7571258) for a way to use FlaUI in PowerShell. – zett42 Feb 17 '23 at 12:55
  • I'm able to locate the "save" button using [Accessibility Insights for Windows](https://github.com/microsoft/accessibility-insights-windows), which seems to suggest that automation is possible. – zett42 Feb 17 '23 at 12:59

1 Answers1

2

As I have commented, MSPaint of Windows 10 and newer versions propably doesn't support the old UIA2 interfaces and requires UIA3 instead.

I've been able to press the "save" button using the FlaUI library (a .NET wrapper for UIA2 and UIA3), after following the steps from the first part of this answer to download its binaries from NuGet.

Add-Type -Path $PSScriptRoot\assemblies\bin\Release\net48\publish\FlaUI.UIA3.dll

# Create UIA3 interface
$automation = [FlaUI.UIA3.UIA3Automation]::new()

# For each mspaint process
foreach( $process in Get-Process mspaint ) {

    # Attach FlaUI to the process
    $app = [FlaUI.Core.Application]::Attach( $process )

    # For each top level window of mspaint
    foreach( $wnd in $app.GetAllTopLevelWindows( $automation ) ) {

        # Filter all descendants - get button named 'Save'
        $wnd.FindAllDescendants() | 
            Where-Object { $_.ControlType -eq 'Button' -and $_.Name -eq 'Save' } | 
            ForEach-Object { 
                # Click the button using the "Invoke" pattern
                $_.Patterns.Invoke.Pattern.Invoke() 
            }  
    }   
}
zett42
  • 25,437
  • 3
  • 35
  • 72