WindowManagementApi 1.1.0
dotnet add package WindowManagementApi --version 1.1.0
NuGet\Install-Package WindowManagementApi -Version 1.1.0
<PackageReference Include="WindowManagementApi" Version="1.1.0" />
<PackageVersion Include="WindowManagementApi" Version="1.1.0" />
<PackageReference Include="WindowManagementApi" />
paket add WindowManagementApi --version 1.1.0
#r "nuget: WindowManagementApi, 1.1.0"
#:package WindowManagementApi@1.1.0
#addin nuget:?package=WindowManagementApi&version=1.1.0
#tool nuget:?package=WindowManagementApi&version=1.1.0
Window Management API
A general-purpose .NET 10 library for programmatic Windows window management with first-class multi-monitor, mixed-DPI support.
Prerequisites
- Windows 10 or 11
- .NET 10.0 or later
- Process must be configured for per-monitor v2 DPI awareness
Quick Start
Standalone usage
using WindowManagement;
await using var manager = WindowManagementFactory.Create();
// List all Alt+Tab windows
var windows = manager.GetAll();
foreach (var w in windows)
Console.WriteLine($"{w.ProcessName}: {w.Title} ({w.Bounds})");
// Snap the foreground window to the left half of the primary monitor
var foreground = manager.GetForeground();
if (foreground != null)
await manager.SnapAsync(foreground, manager.Monitors.Primary, SnapPosition.Left);
With dependency injection
using WindowManagement.DependencyInjection;
services.AddWindowManagement();
With Autofac
using WindowManagement.DependencyInjection;
builder.RegisterModule(new WindowManagementModule());
Then inject IWindowManager:
public class MyService(IWindowManager windowManager)
{
public async Task SnapToLeft()
{
var foreground = windowManager.GetForeground();
if (foreground != null)
await windowManager.SnapAsync(foreground, windowManager.Monitors.Primary, SnapPosition.Left);
}
}
Window Filtering
// Default: Alt+Tab window set
var windows = manager.GetAll();
// Filter by process
var windows = manager.GetAll(f => f.WithProcess("notepad"));
// Filter by title with wildcards
var windows = manager.GetAll(f => f.WithTitle("*.txt*"));
// Exclude minimized windows
var windows = manager.GetAll(f => f.ExcludeMinimized());
// Raw enumeration (no Alt+Tab filtering)
var windows = manager.GetAll(f => f.Unfiltered());
// Custom predicate
var windows = manager.GetAll(f => f.Where(w => w.Bounds.Width > 500));
Window Properties
IWindow provides rich snapshot data for each window:
var window = manager.GetForeground();
if (window != null)
{
Console.WriteLine($"Title: {window.Title}");
Console.WriteLine($"Process: {window.ProcessName} (PID {window.ProcessId})");
Console.WriteLine($"Bounds: {window.Bounds}, Client: {window.ClientBounds}");
Console.WriteLine($"State: {window.State}, Resizable: {window.IsResizable}");
Console.WriteLine($"DPI: {window.Dpi}, Awareness: {window.DpiAwareness}");
Console.WriteLine($"Topmost: {window.IsTopmost}, ClickThrough: {window.IsClickThrough}");
}
DPI Awareness
Check a window's DPI awareness level to handle cross-monitor positioning of legacy apps:
if (window.DpiAwareness == DpiAwareness.Unaware)
Console.WriteLine("Legacy app — Windows virtualizes DPI for this window");
Values: Unaware, SystemAware, PerMonitorAware, PerMonitorAwareV2
Extended Window Styles
Toggle click-through and tool-window styles:
// Make an overlay window click-through (WS_EX_TRANSPARENT)
await manager.SetClickThroughAsync(window, true);
// Hide window from Alt+Tab (WS_EX_TOOLWINDOW)
await manager.SetToolWindowAsync(window, true);
For advanced style manipulation, use the low-level API:
var style = windowApi.GetExtendedStyle(handle);
style |= ExtendedWindowStyle.NoActivate;
windowApi.SetExtendedStyle(handle, style);
Window Events (R3)
manager.Created.Subscribe(e => Console.WriteLine($"Created: {e.Title}"));
manager.Moved.Subscribe(e => Console.WriteLine($"Moved: {e.Title} -> {e.NewBounds}"));
manager.Monitors.Connected.Subscribe(e => Console.WriteLine($"Monitor connected: {e.DeviceName}"));
Move/Size Events
Detect when a user starts and finishes dragging or resizing a window:
manager.MoveSizeStarted.Subscribe(e =>
Console.WriteLine($"Drag started: {e.Title}"));
manager.MoveSizeEnded.Subscribe(e =>
Console.WriteLine($"Drag ended: {e.Title} from {e.OldBounds} to {e.NewBounds}"));
Error Handling
The library throws WindowManagementException when Win32 operations fail (e.g., SetWindowPos, GetWindowRect). WindowNotFoundException (a subclass) is thrown when a window handle becomes invalid.
try
{
await manager.SnapAsync(window, monitor, SnapPosition.Left);
}
catch (WindowNotFoundException)
{
// Window was closed
}
catch (WindowManagementException ex)
{
// Win32 operation failed
Console.WriteLine(ex.Message);
}
WindowRect enforces non-negative Width and Height:
var rect = new WindowRect(0, 0, 800, 600); // OK
var bad = new WindowRect(0, 0, -1, 600); // throws ArgumentOutOfRangeException
var also = rect with { Width = -1 }; // throws ArgumentOutOfRangeException
Low-Level API
For advanced consumers who need direct Win32 access with correct DPI math:
// Inject or resolve
IWindowApi windowApi = ...;
IDisplayApi displayApi = ...;
var handles = windowApi.Enumerate(altTabOnly: true);
var bounds = windowApi.GetBounds(handle);
windowApi.SetBounds(handle, new WindowRect(0, 0, 800, 600));
// DPI awareness per window
var awareness = windowApi.GetDpiAwareness(handle); // Unaware, SystemAware, PerMonitorAware, PerMonitorAwareV2
// Extended window styles
var style = windowApi.GetExtendedStyle(handle);
windowApi.SetExtendedStyle(handle, style | ExtendedWindowStyle.Transparent);
var monitors = displayApi.GetAll();
var logical = displayApi.PhysicalToLogical(bounds, monitor.Handle);
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0-windows7.0 is compatible. |
-
net10.0-windows7.0
- Autofac (>= 8.4.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.5)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.5)
- Microsoft.Extensions.Options (>= 10.0.5)
- Microsoft.Win32.SystemEvents (>= 9.0.14)
- R3 (>= 1.3.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.