105 lines
4.0 KiB
PowerShell
105 lines
4.0 KiB
PowerShell
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
|