feat(scanner): complete localized artifact quality checkpoint
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[int]$ProcessId,
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$OutputPath,
|
||||
[int]$ClickX = -1,
|
||||
[int]$ClickY = -1,
|
||||
[int]$WaitAfterClickMs = 700,
|
||||
[switch]$CloseAfterCapture
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
trap {
|
||||
$errorPath = [IO.Path]::GetFullPath("$OutputPath.error.txt")
|
||||
New-Item -ItemType Directory -Force -Path (Split-Path -Parent $errorPath) | Out-Null
|
||||
[string]$_.Exception.Message | Set-Content -LiteralPath $errorPath -Encoding UTF8
|
||||
exit 1
|
||||
}
|
||||
|
||||
Add-Type -TypeDefinition @'
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
public static class WindowCaptureNative {
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct RECT { public int Left; public int Top; public int Right; public int Bottom; }
|
||||
[DllImport("user32.dll")] public static extern bool GetWindowRect(IntPtr hWnd, out RECT rect);
|
||||
[DllImport("user32.dll")] public static extern bool SetForegroundWindow(IntPtr hWnd);
|
||||
[DllImport("user32.dll")] public static extern bool ShowWindowAsync(IntPtr hWnd, int command);
|
||||
[DllImport("user32.dll")] public static extern bool PrintWindow(IntPtr hWnd, IntPtr hdcBlt, uint flags);
|
||||
[DllImport("user32.dll")] public static extern IntPtr GetForegroundWindow();
|
||||
[DllImport("user32.dll")] public static extern bool SetCursorPos(int x, int y);
|
||||
[DllImport("user32.dll")] public static extern void mouse_event(uint flags, uint dx, uint dy, uint data, UIntPtr extraInfo);
|
||||
[DllImport("user32.dll")] public static extern bool PostMessage(IntPtr hWnd, uint message, UIntPtr wParam, IntPtr lParam);
|
||||
}
|
||||
'@
|
||||
Add-Type -AssemblyName System.Drawing
|
||||
|
||||
$process = Get-Process -Id $ProcessId -ErrorAction Stop
|
||||
$handle = [IntPtr]$process.MainWindowHandle
|
||||
if ($handle -eq [IntPtr]::Zero) { throw "Process $ProcessId has no main window." }
|
||||
|
||||
[WindowCaptureNative]::ShowWindowAsync($handle, 9) | Out-Null
|
||||
[WindowCaptureNative]::SetForegroundWindow($handle) | Out-Null
|
||||
Start-Sleep -Milliseconds 700
|
||||
|
||||
$rect = New-Object WindowCaptureNative+RECT
|
||||
if (-not [WindowCaptureNative]::GetWindowRect($handle, [ref]$rect)) { throw "GetWindowRect failed." }
|
||||
$width = $rect.Right - $rect.Left
|
||||
$height = $rect.Bottom - $rect.Top
|
||||
if ($width -lt 1 -or $height -lt 1) { throw "Window dimensions are invalid: ${width}x${height}." }
|
||||
|
||||
$clicked = $false
|
||||
if ($ClickX -ge 0 -or $ClickY -ge 0) {
|
||||
if ($ClickX -lt 0 -or $ClickY -lt 0 -or $ClickX -ge $width -or $ClickY -ge $height) {
|
||||
throw "Click coordinates must stay inside the target window."
|
||||
}
|
||||
if ([WindowCaptureNative]::GetForegroundWindow() -ne $handle) {
|
||||
throw "Target process is not foreground; no click was sent."
|
||||
}
|
||||
[WindowCaptureNative]::SetCursorPos($rect.Left + $ClickX, $rect.Top + $ClickY) | Out-Null
|
||||
[WindowCaptureNative]::mouse_event(0x0002, 0, 0, 0, [UIntPtr]::Zero)
|
||||
[WindowCaptureNative]::mouse_event(0x0004, 0, 0, 0, [UIntPtr]::Zero)
|
||||
$clicked = $true
|
||||
Start-Sleep -Milliseconds ([Math]::Max(0, $WaitAfterClickMs))
|
||||
}
|
||||
|
||||
$resolvedOutput = [IO.Path]::GetFullPath($OutputPath)
|
||||
$outputDirectory = Split-Path -Parent $resolvedOutput
|
||||
New-Item -ItemType Directory -Force -Path $outputDirectory | Out-Null
|
||||
$bitmap = New-Object System.Drawing.Bitmap $width, $height
|
||||
$graphics = [System.Drawing.Graphics]::FromImage($bitmap)
|
||||
$printed = $false
|
||||
try {
|
||||
$hdc = $graphics.GetHdc()
|
||||
try {
|
||||
$printed = [WindowCaptureNative]::PrintWindow($handle, $hdc, 2)
|
||||
} finally {
|
||||
$graphics.ReleaseHdc($hdc)
|
||||
}
|
||||
if (-not $printed) {
|
||||
$graphics.CopyFromScreen($rect.Left, $rect.Top, 0, 0, $bitmap.Size)
|
||||
}
|
||||
$bitmap.Save($resolvedOutput, [System.Drawing.Imaging.ImageFormat]::Png)
|
||||
} finally {
|
||||
$graphics.Dispose()
|
||||
$bitmap.Dispose()
|
||||
}
|
||||
|
||||
$closeRequested = $false
|
||||
if ($CloseAfterCapture) {
|
||||
$closeRequested = [WindowCaptureNative]::PostMessage($handle, 0x0010, [UIntPtr]::Zero, [IntPtr]::Zero)
|
||||
}
|
||||
|
||||
[pscustomobject]@{
|
||||
ok = $true
|
||||
processId = $ProcessId
|
||||
title = $process.MainWindowTitle
|
||||
width = $width
|
||||
height = $height
|
||||
printWindow = $printed
|
||||
clicked = $clicked
|
||||
closeRequested = $closeRequested
|
||||
outputPath = $resolvedOutput
|
||||
} | ConvertTo-Json
|
||||
Reference in New Issue
Block a user