# Shared helpers for the Windows test scripts (screenshots, input, UI Automation). $ErrorActionPreference = 'Continue' $ProgressPreference = 'SilentlyContinue' $root = Split-Path -Parent $MyInvocation.MyCommand.Path $out = Join-Path $root $(if ($OutName) { $OutName } else { 'results' }) New-Item -ItemType Directory -Force -Path $out | Out-Null $log = Join-Path $out 'run-log.txt' $facts = [ordered]@{} function Log($m) { $line = "[{0:HH:mm:ss}] {1}" -f (Get-Date), $m; Write-Host $line; Add-Content -Path $log -Value $line } Add-Type -AssemblyName System.Windows.Forms, System.Drawing, UIAutomationClient, UIAutomationTypes Add-Type @" using System; using System.Runtime.InteropServices; public static class N { [DllImport("user32.dll")] public static extern bool SetProcessDPIAware(); [DllImport("user32.dll", CharSet = CharSet.Unicode)] public static extern int SystemParametersInfo(int a, int b, string c, int d); [DllImport("user32.dll")] public static extern void keybd_event(byte vk, byte scan, int flags, IntPtr extra); [DllImport("user32.dll")] public static extern bool SetCursorPos(int x, int y); [DllImport("user32.dll")] public static extern void mouse_event(int f, int x, int y, int d, IntPtr e); [DllImport("user32.dll", CharSet = CharSet.Unicode)] public static extern IntPtr FindWindow(string cls, string title); [DllImport("user32.dll")] public static extern bool GetWindowRect(IntPtr h, out RECT r); [DllImport("user32.dll")] public static extern bool ShowWindow(IntPtr h, int cmd); [DllImport("user32.dll")] public static extern bool SetForegroundWindow(IntPtr h); [StructLayout(LayoutKind.Sequential)] public struct RECT { public int Left, Top, Right, Bottom; } } "@ [N]::SetProcessDPIAware() | Out-Null function Shot($name) { try { $b = [System.Windows.Forms.Screen]::PrimaryScreen.Bounds $bmp = New-Object System.Drawing.Bitmap $b.Width, $b.Height $g = [System.Drawing.Graphics]::FromImage($bmp) $g.CopyFromScreen($b.Location, [System.Drawing.Point]::Empty, $b.Size) $bmp.Save((Join-Path $out "$name.png"), [System.Drawing.Imaging.ImageFormat]::Png) # Taskbar close-up: bottom 120 px at 2x. $h = [Math]::Min(120, $b.Height) $crop = $bmp.Clone((New-Object System.Drawing.Rectangle 0, ($b.Height - $h), $b.Width, $h), $bmp.PixelFormat) $big = New-Object System.Drawing.Bitmap ($crop.Width), ($crop.Height * 2) $g2 = [System.Drawing.Graphics]::FromImage($big) $g2.InterpolationMode = 'NearestNeighbor' $g2.DrawImage($crop, 0, 0, $crop.Width, $crop.Height * 2) $big.Save((Join-Path $out "$name-taskbar.png"), [System.Drawing.Imaging.ImageFormat]::Png) $g.Dispose(); $g2.Dispose(); $bmp.Dispose(); $crop.Dispose(); $big.Dispose() Log "screenshot $name ($($b.Width)x$($b.Height))" } catch { Log "screenshot $name FAILED: $_" } } function Key([byte[]]$keys) { foreach ($k in $keys) { [N]::keybd_event($k, 0, 0, [IntPtr]::Zero); Start-Sleep -Milliseconds 40 } [array]::Reverse($keys) foreach ($k in $keys) { [N]::keybd_event($k, 0, 2, [IntPtr]::Zero); Start-Sleep -Milliseconds 40 } } $UIA = [System.Windows.Automation.AutomationElement] function FindName($name, $timeout = 20) { $cond = New-Object System.Windows.Automation.PropertyCondition($UIA::NameProperty, $name) $end = (Get-Date).AddSeconds($timeout) while ((Get-Date) -lt $end) { try { $el = $UIA::RootElement.FindFirst([System.Windows.Automation.TreeScope]::Descendants, $cond); if ($el) { return $el } } catch { } Start-Sleep -Milliseconds 700 } return $null } function Invoke-El($el) { try { $el.GetCurrentPattern([System.Windows.Automation.InvokePattern]::Pattern).Invoke(); return $true } catch { } try { $r = $el.Current.BoundingRectangle; Click ([int]($r.X + $r.Width / 2)) ([int]($r.Y + $r.Height / 2)) $false; return $true } catch { return $false } } function Click($x, $y, $right) { [N]::SetCursorPos($x, $y) | Out-Null; Start-Sleep -Milliseconds 150 if ($right) { [N]::mouse_event(0x08, 0, 0, 0, [IntPtr]::Zero); [N]::mouse_event(0x10, 0, 0, 0, [IntPtr]::Zero) } else { [N]::mouse_event(0x02, 0, 0, 0, [IntPtr]::Zero); [N]::mouse_event(0x04, 0, 0, 0, [IntPtr]::Zero) } }