Microsoft.Windows.SDK.BuildTools.WinApp.UIAutomation
0.7.0
Prefix Reserved
dotnet add package Microsoft.Windows.SDK.BuildTools.WinApp.UIAutomation --version 0.7.0
NuGet\Install-Package Microsoft.Windows.SDK.BuildTools.WinApp.UIAutomation -Version 0.7.0
<PackageReference Include="Microsoft.Windows.SDK.BuildTools.WinApp.UIAutomation" Version="0.7.0" />
<PackageVersion Include="Microsoft.Windows.SDK.BuildTools.WinApp.UIAutomation" Version="0.7.0" />
<PackageReference Include="Microsoft.Windows.SDK.BuildTools.WinApp.UIAutomation" />
paket add Microsoft.Windows.SDK.BuildTools.WinApp.UIAutomation --version 0.7.0
#r "nuget: Microsoft.Windows.SDK.BuildTools.WinApp.UIAutomation, 0.7.0"
#:package Microsoft.Windows.SDK.BuildTools.WinApp.UIAutomation@0.7.0
#addin nuget:?package=Microsoft.Windows.SDK.BuildTools.WinApp.UIAutomation&version=0.7.0
#tool nuget:?package=Microsoft.Windows.SDK.BuildTools.WinApp.UIAutomation&version=0.7.0
Microsoft.Windows.SDK.BuildTools.WinApp.UIAutomation
Inspect and drive any running Windows desktop app from code — the UI Automation engine behind the
winapp ui commands, packaged as a library.
This package does not coordinate with other automation on the desktop. The
winappCLI layers cooperative desktop turns on top of this engine so concurrentwinapp uiworkflows cannot steal each other's focus or dismiss each other's menus. That arbitration lives in the CLI, not here. Code calling these APIs directly does not participate in it: it drives the desktop immediately, so if you run it alongsidewinapp ui, or alongside another copy of itself, you are responsible for serializing the two — or for running on a dedicated interactive desktop, as described below.
dotnet add package Microsoft.Windows.SDK.BuildTools.WinApp.UIAutomation
dotnet add package Microsoft.Extensions.DependencyInjection
dotnet add package Microsoft.Extensions.Logging
using Microsoft.Windows.SDK.BuildTools.WinApp.UIAutomation;
using Microsoft.Extensions.DependencyInjection;
var services = new ServiceCollection()
.AddLogging()
.AddWinAppUiAutomation()
.BuildServiceProvider();
var ui = services.GetRequiredService<IUiAutomation>();
var resolver = services.GetRequiredService<IUiTargetResolver>();
var target = await resolver.ResolveAsync("notepad", hwnd: null, CancellationToken.None);
var button = await ui.FindSingleElementAsync(target, new UiSelector { Query = "Save" }, CancellationToken.None);
await ui.InvokeAsync(target, button!, CancellationToken.None);
What you get
- Element inspection and search — walk the UIA tree, or find one element by a stable semantic
slug (
btn-save-a1b2) or a plain-text query. - Interaction through UIA patterns — invoke, set value, focus, scroll, scroll-into-view, read text.
- Input injection — keyboard, mouse, touch and pen, including gestures.
- Window capture — screenshots as raw BGRA pixels.
Video recording is a separate package,
Microsoft.Windows.SDK.BuildTools.WinApp.UIAutomation.Recording, so that projects which only
inspect and drive UI do not take a dependency on SkiaSharp.
Choosing a target framework
The package ships two targets with the same public API:
| Target framework | Screenshots | Continuous frame capture | Added to your app |
|---|---|---|---|
net10.0-windows |
PrintWindow (GDI) |
not available | ~1.5 MB |
net10.0-windows10.0.19041.0 |
Windows Graphics Capture, falling back to PrintWindow |
available | ~1.5 MB + ~24 MB Windows SDK projection |
Prefer net10.0-windows unless you need Graphics Capture. Graphics Capture matters when you have
to screenshot a window that is occluded or in the background, or one whose content is
GPU-composited (WinUI 3, DirectX, video), where PrintWindow can return a blank frame.
IWindowCapture.IsFrameCaptureSupported reports which implementation you got at runtime.
Native desktop pixels
IWindowCapture.GetDesktopBounds() returns the current input desktop's virtual-screen rectangle.
Pass its origin and size to CaptureScreenPixels, using that same size for the encoder and
display dimensions when you need unscaled BGRA pixels. Measure again afterward and discard the
frame if the bounds changed. These operations do not activate a window. They require an unlocked
interactive input desktop and a per-monitor-DPI-aware calling process.
CaptureCoordinates describes a source screen rectangle and its content rectangle within an image.
ToScreenPoint maps an image pixel center to an integer screen pixel and rejects padding.
The screen origin may be negative; right and bottom bounds are exclusive.
Using it with MSTest
The package pairs with MSTest.Windows.UIAutomation, which launches the app and hands you the main
window as a UIA2 AutomationElement. Bridge into this library through the window handle:
[STATestClass]
public class CalculatorTests : WindowTest
{
protected override ProcessStartInfo CreateProcessStartInfo() => new("calc.exe");
[TestMethod]
public async Task Clicking_Seven_ShowsSeven()
{
var target = UiTarget.FromWindowHandle(MainWindow.Current.NativeWindowHandle);
var seven = await _ui.FindSingleElementAsync(target, new UiSelector { Query = "Seven" }, default);
await _ui.InvokeAsync(target, seven!, default);
}
}
Your test project must target a framework this package supports — for example net10.0-windows.
Input injection drives the real mouse and keyboard
IKeyboardInput, IMouseInput, and IPointerInput send system-wide input, exactly as a person at
the machine would: clicks land wherever the cursor is moved, and keystrokes go to whichever window
holds focus at that instant. If a popup, a UAC prompt, or a screen lock steals focus mid-test, the
input goes there instead of your app.
Run this on a dedicated interactive desktop rather than the one you are working on, and note that injection does nothing useful over a disconnected RDP session, where there is no live desktop to receive it.
ForegroundGuard exposes the two checks these paths need, and they are deliberately different:
ForegroundBelongsTo(hwnd)— the strict one, for input. It accepts only the target window or the top-level root that owns it, because a dialog in front would swallow your keystrokes.ForegroundIsCapturableFor(hwnd)— the capture one, for screen capture and screen recording. It also accepts a foreground window whose owner chain reaches the target, because a modal dialog the target owns is part of that app's UI and is sitting on the pixels you asked for. An unrelated window is still refused, so you never get a picture of somebody else's app labelled as yours.
Requirements
Windows 10 version 1809 or later for synthetic pen and touch injection; other features work on earlier Windows 10 releases.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0-windows7.0 is compatible. net10.0-windows10.0.19041 is compatible. |
-
net10.0-windows10.0.19041
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.5)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.5)
-
net10.0-windows7.0
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.5)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.5)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Microsoft.Windows.SDK.BuildTools.WinApp.UIAutomation:
| Package | Downloads |
|---|---|
|
Microsoft.Windows.SDK.BuildTools.WinApp.UIAutomation.Recording
Screen and window video recording for Windows UI automation: captures a window or element region at a fixed cadence and encodes it to H.264 MP4 via Media Foundation, with optional timestamped JPEG frame bundles. Split from Microsoft.Windows.SDK.BuildTools.WinApp.UIAutomation so that projects which only inspect and drive UI do not take a dependency on SkiaSharp. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.7.0 | 47 | 9/24/2026 |
| 0.6.3-prerelease.90 | 50 | 9/23/2026 |
| 0.6.3-prerelease.88 | 46 | 9/23/2026 |