lepoco/wpfui · error · InvalidOperationException

Unable to determine the window source.

Error message

Unable to determine the window source.

What it means

Thrown in the ObservedWindow constructor when HwndSource.FromHwnd(handle) returns null, meaning the given HWND has no associated WPF HwndSource. The class caches the source to read RootVisual and attach hooks, so without it the watcher cannot operate on that window.

Source

Thrown at src/Wpf.Ui/Appearance/ObservedWindow.cs:32

{
    private readonly HwndSource _source;

    /// <summary>
    /// Initializes a new instance of the <see cref="ObservedWindow"/> class.
    /// </summary>
    /// <param name="handle">The handle of the window.</param>
    /// <param name="backdrop">The backdrop type of the window.</param>
    /// <param name="updateAccents">Indicates whether to update accents.</param>
    public ObservedWindow(IntPtr handle, WindowBackdropType backdrop, bool updateAccents)
    {
        Handle = handle;
        Backdrop = backdrop;
        UpdateAccents = updateAccents;
        HasHook = false;

        HwndSource? windowSource = HwndSource.FromHwnd(handle);
        _source =
            windowSource ?? throw new InvalidOperationException("Unable to determine the window source.");
    }

    /// <summary>
    /// Gets the root visual of the window.
    /// </summary>
    public Window? RootVisual => (Window?)_source.RootVisual;

    /// <summary>
    /// Gets the handle of the window.
    /// </summary>
    public IntPtr Handle { get; }

    /// <summary>
    /// Gets the backdrop type of the window.
    /// </summary>
    public WindowBackdropType Backdrop { get; }

    /// <summary>

View on GitHub (pinned to ffebacd610)

Solutions

  1. Only observe WPF System.Windows.Window instances and ensure they are loaded (IsLoaded true) before calling Watch/Observe so the HWND is valid.
  2. Prefer the Window-based overloads of SystemThemeWatcher rather than constructing ObservedWindow with a raw handle.
  3. If you must use a handle, confirm HwndSource.FromHwnd(handle) is non-null before constructing ObservedWindow.

Example fix

// before
var obs = new ObservedWindow(someHandle, backdrop, true);

// after
if (HwndSource.FromHwnd(someHandle) is { } src)
{
    var obs = new ObservedWindow(someHandle, backdrop, true);
}
else
{
    // handle is invalid or non-WPF; skip observing
}
Defensive patterns

Strategy: validation

Validate before calling

if (HwndSource.FromHwnd(handle) is null) { /* skip or log; do not construct ObservedWindow */ }

Type guard

static bool IsWpfHwnd(IntPtr h) => h != IntPtr.Zero && HwndSource.FromHwnd(h) is not null;

Prevention

When it happens

Trigger: SystemThemeWatcher.Observe/Watch is called with an IntPtr that is zero, stale, belongs to a non-WPF window, or whose HwndSource was already disposed. FromHwnd only resolves sources created by WPF and still alive.

Common situations: Passing a handle from a WinForms or native window, calling Watch after the window has been closed/disposed, or passing IntPtr.Zero because the window was not yet realized. Cross-process handles also return null.

Related errors


AI-assisted analysis of lepoco/wpfui@ffebacd610 (2026-08-13). Data as JSON: /api/errors/529da76f64521887. Report an issue: GitHub.