• Articles
  • Api Documentation
Show / Hide Table of Contents
  • Introduction
  • Window Management
  • Clipboard Usage
  • DPI Awareness
  • Input Handling
  • Common Scenarios

Window Management Guide

This guide covers working with windows using the Dapplo.Windows package.

Overview

The Dapplo.Windows package provides the InteropWindow class, which represents a Windows window and provides methods for querying and manipulating it.

Getting Window Information

From Window Handle

using Dapplo.Windows.Desktop;
using Dapplo.Windows.User32;

// Get the foreground window
IntPtr handle = User32Api.GetForegroundWindow();
IInteropWindow window = InteropWindow.FromHandle(handle);

// Populate all window properties
window.Fill();

// Access properties
Console.WriteLine($"Title: {window.Caption}");
Console.WriteLine($"Class: {window.Classname}");
Console.WriteLine($"Process ID: {window.ProcessId}");
Console.WriteLine($"Bounds: {window.Bounds}");

Selective Property Loading

For better performance, load only the properties you need:

using Dapplo.Windows.Desktop;
using Dapplo.Windows.Enums;

var window = InteropWindow.FromHandle(handle);

// Load only caption and bounds
window.Fill(InteropWindowRetrieveSettings.Caption | 
            InteropWindowRetrieveSettings.Info);

Console.WriteLine($"{window.Caption} at {window.Bounds}");

Enumerating Windows

Get All Top-Level Windows

using Dapplo.Windows.Desktop;
using System.Linq;

var windows = InteropWindowQuery.GetTopLevelWindows();

foreach (var window in windows)
{
    Console.WriteLine($"{window.Caption} ({window.Classname})");
}

Filter Windows

using Dapplo.Windows.Desktop;

// Get all visible windows
var visibleWindows = InteropWindowQuery.GetTopLevelWindows()
    .Where(w => w.IsVisible())
    .ToList();

// Get windows by process name
var notepadWindows = InteropWindowQuery.GetTopLevelWindows()
    .Where(w => w.GetProcessPath()?.Contains("notepad.exe") ?? false)
    .ToList();

// Get windows by class name
var explorerWindows = InteropWindowQuery.GetTopLevelWindows()
    .Where(w => w.GetClassname() == "CabinetWClass")
    .ToList();

Get Child Windows

using Dapplo.Windows.Desktop;

var parentWindow = InteropWindow.FromHandle(handle);
parentWindow.Fill(InteropWindowRetrieveSettings.Children);

foreach (var child in parentWindow.Children)
{
    Console.WriteLine($"Child: {child.Caption} ({child.Classname})");
}

Window Manipulation

Show/Hide Windows

using Dapplo.Windows.Desktop;
using Dapplo.Windows.User32.Enums;

var window = InteropWindow.FromHandle(handle);

// Show the window
window.Show();

// Hide the window
window.Hide();

// Minimize
window.Minimize();

// Maximize
window.Maximize();

// Restore (unmaximize/unminimize)
window.Restore();

Move and Resize

using Dapplo.Windows.Desktop;
using Dapplo.Windows.Common.Structs;

var window = InteropWindow.FromHandle(handle);

// Move window
window.MoveTo(new NativePoint(100, 100));

// Resize window
window.Resize(new NativeSize(800, 600));

// Move and resize together
window.SetPlacement(new NativeRect(100, 100, 900, 700));

Bring to Front

using Dapplo.Windows.Desktop;

var window = InteropWindow.FromHandle(handle);

// Bring window to foreground
window.ToForeground();

// Flash window in taskbar
window.Flash();

Monitoring Window Events

Window Creation and Destruction

using Dapplo.Windows.Desktop;
using System;

// Monitor window creation
var creationSubscription = WinEventHook.Create(WinEvents.EVENT_OBJECT_CREATE)
    .Subscribe(winEvent =>
    {
        var window = InteropWindow.FromHandle(winEvent.Handle);
        Console.WriteLine($"Window created: {window.GetCaption()}");
    });

// Monitor window destruction
var destructionSubscription = WinEventHook.Create(WinEvents.EVENT_OBJECT_DESTROY)
    .Subscribe(winEvent =>
    {
        Console.WriteLine($"Window destroyed: {winEvent.Handle}");
    });

// Clean up when done
creationSubscription.Dispose();
destructionSubscription.Dispose();

Window Title Changes

using Dapplo.Windows.Desktop;

var subscription = WinEventHook.Create(WinEvents.EVENT_OBJECT_NAMECHANGE)
    .Subscribe(winEvent =>
    {
        var window = InteropWindow.FromHandle(winEvent.Handle);
        Console.WriteLine($"Title changed: {window.GetCaption()}");
    });

Foreground Window Changes

using Dapplo.Windows.Desktop;

var subscription = WinEventHook.Create(WinEvents.EVENT_SYSTEM_FOREGROUND)
    .Subscribe(winEvent =>
    {
        var window = InteropWindow.FromHandle(winEvent.Handle);
        Console.WriteLine($"Foreground window: {window.GetCaption()}");
    });

Window Location/Size Changes

using Dapplo.Windows.Desktop;

var subscription = WinEventHook.Create(WinEvents.EVENT_OBJECT_LOCATIONCHANGE)
    .Subscribe(winEvent =>
    {
        var window = InteropWindow.FromHandle(winEvent.Handle);
        window.Fill(InteropWindowRetrieveSettings.Info);
        Console.WriteLine($"Window moved/resized: {window.Caption} at {window.Bounds}");
    });

Filter Events by Process or Window

using Dapplo.Windows.Desktop;
using System.Reactive.Linq;

// Only monitor specific window
var targetHandle = /* your window handle */;
var subscription = WinEventHook.Create(WinEvents.EVENT_OBJECT_NAMECHANGE)
    .Where(winEvent => winEvent.Handle == targetHandle)
    .Subscribe(winEvent =>
    {
        Console.WriteLine("Target window title changed");
    });

// Only monitor windows from specific process
var targetProcessId = /* your process ID */;
var processSubscription = WinEventHook.Create(WinEvents.EVENT_OBJECT_CREATE)
    .Where(winEvent => 
    {
        var window = InteropWindow.FromHandle(winEvent.Handle);
        return window.GetProcessId() == targetProcessId;
    })
    .Subscribe(winEvent =>
    {
        Console.WriteLine("Window created in target process");
    });

Advanced Scenarios

Find Window by Title

using Dapplo.Windows.Desktop;
using System.Linq;

string targetTitle = "Notepad";
var window = InteropWindowQuery.GetTopLevelWindows()
    .FirstOrDefault(w => w.GetCaption()?.Contains(targetTitle) ?? false);

if (window != null)
{
    Console.WriteLine($"Found window: {window.Caption}");
}

Get Windows Stacking Order (Z-Order)

using Dapplo.Windows.Desktop;

var desktop = InteropWindow.GetDesktopWindow();
desktop.Fill(InteropWindowRetrieveSettings.ZOrderedChildren);

Console.WriteLine("Windows in Z-order (top to bottom):");
foreach (var window in desktop.ZOrderedChildren.Where(w => w.IsVisible()))
{
    Console.WriteLine($"  {window.Caption}");
}

Window Screenshots

using Dapplo.Windows.Desktop;
using Dapplo.Windows.Gdi32;
using System.Drawing;
using System.Drawing.Imaging;

var window = InteropWindow.FromHandle(handle);
window.Fill(InteropWindowRetrieveSettings.Info);

// Capture window content
using (var bitmap = window.Capture())
{
    bitmap.Save("window_capture.png", ImageFormat.Png);
}

Check Window State

using Dapplo.Windows.Desktop;

var window = InteropWindow.FromHandle(handle);

if (window.IsVisible())
{
    Console.WriteLine("Window is visible");
}

if (window.IsMinimized())
{
    Console.WriteLine("Window is minimized");
}

if (window.IsMaximized())
{
    Console.WriteLine("Window is maximized");
}

if (window.IsAppWindow())
{
    Console.WriteLine("Window is an application window");
}

Best Practices

1. Check Window Validity

Always check if a window still exists before using it:

var window = InteropWindow.FromHandle(handle);

if (window.Exists())
{
    // Safe to use the window
    Console.WriteLine(window.GetCaption());
}

2. Dispose Subscriptions

Always dispose of event subscriptions when done:

var subscription = WinEventHook.Create(WinEvents.EVENT_OBJECT_CREATE)
    .Subscribe(HandleWindowCreated);

// Later, when cleaning up
subscription.Dispose();

3. Handle Exceptions

Windows can be destroyed or become invalid:

try
{
    var caption = window.GetCaption();
}
catch (Win32Exception ex)
{
    Console.WriteLine($"Error accessing window: {ex.Message}");
}

4. Cache Window Information

If you're repeatedly accessing window properties, cache them:

var window = InteropWindow.FromHandle(handle);
window.Fill(); // Load all properties at once

// Now properties are cached
var caption = window.Caption;
var bounds = window.Bounds;
var processId = window.ProcessId;

See Also

  • API Reference
  • Getting Started
  • Common Scenarios
  • Improve this Doc
In This Article
Back to top Copyright © 2017 Dapplo