dotnet/wpf · error · InvalidOperationException

SR.HwndHostDoesNotSupportChildKeyboardSinks

Error message

SR.HwndHostDoesNotSupportChildKeyboardSinks

What it means

HwndHost does not support child keyboard input sinks: its virtual RegisterKeyboardInputSinkCore deliberately throws InvalidOperationException with SR.HwndHostDoesNotSupportChildKeyboardSinks. Unlike HwndSource, an HwndHost cannot register nested IKeyboardInputSink components for Tab/keyboard routing.

Solutions

  1. Do not register child keyboard sinks with HwndHost; remove the RegisterKeyboardInputSink call.
  2. Restructure so the child is hosted in an HwndSource if sink registration is required.
  3. Override RegisterKeyboardInputSinkCore in a derived HwndHost class to implement sink support yourself.
  4. Handle keyboard interop via standard focus/Tab routing (e.g. IKeyboardInputSink on the top-level HwndSource) instead.

Example fix

// before
var site = ((IKeyboardInputSink)hwndHost).RegisterKeyboardInputSink(childSink);
// after
// HwndHost does not support child sinks; rely on the owning HwndSource
var site = ((IKeyboardInputSink)hwndSource).RegisterKeyboardInputSink(childSink);
Defensive patterns

Strategy: type-guard

Validate before calling

if (host is HwndHost)
    throw new NotSupportedException("HwndHost does not support child keyboard sinks");

Type guard

bool SupportsChildSinks(IKeyboardInputSink sink) => sink is HwndSource;

Try / catch

try
{
    site = ((IKeyboardInputSink)sinkContainer).RegisterKeyboardInputSink(childSink);
}
catch (InvalidOperationException)
{
    // fall back to top-level HwndSource sink registration
}

Prevention

When it happens

Trigger: Calling IKeyboardInputSink.RegisterKeyboardInputSink (or the protected RegisterKeyboardInputSinkCore) with a child sink on an HwndHost instance, e.g. hosting a component that tries to register itself as a keyboard sink with an HwndHost-based control.

Common situations: Embedding WindowsFormsHost or other sink-registering children inside an HwndHost-derived control and relying on cross-boundary keyboard sink registration; migrating code from HwndSource to HwndHost.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14). Data as JSON: /api/errors/c901644c24227ea5. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Interop/HwndHost.cs:209

        // explicit interface implementations (that do have the property of being hidden from the public
        // contract, which limits IntelliSense on derived types like WebBrowser) while sticking protected
        // virtuals next to them. Those virtuals contain our base implementation, while the explicit
        // interface implementation methods do call trivially into the virtuals.
        //
        // This comment outlines the security rationale applied to those methods.
        //
        // <SecurityNote Name="IKeyboardInputSink_Implementation">
        //     The security attributes on the virtual methods within this region mirror the corresponding
        //     IKeyboardInputSink methods; customers can override those methods, so we insert a LinkDemand
        //     to encourage them to have a LinkDemand too (via FxCop).

        /// <summary>
        ///     Registers a IKeyboardInputSink with the HwndSource in order
        ///     to retreive a unique IKeyboardInputSite for it.
        /// </summary>
        protected virtual IKeyboardInputSite RegisterKeyboardInputSinkCore(IKeyboardInputSink sink)
        {
            throw new InvalidOperationException(SR.HwndHostDoesNotSupportChildKeyboardSinks);
        }

        IKeyboardInputSite IKeyboardInputSink.RegisterKeyboardInputSink(IKeyboardInputSink sink)
        {
            return RegisterKeyboardInputSinkCore(sink);
        }

        /// <summary>
        ///     Gives the component a chance to process keyboard input.
        ///     Return value is true if handled, false if not.  Components
        ///     will generally call a child component's TranslateAccelerator
        ///     if they can't handle the input themselves.  The message must
        ///     either be WM_KEYDOWN or WM_SYSKEYDOWN.  It is illegal to
        ///     modify the MSG structure, it's passed by reference only as
        ///     a performance optimization.
        /// </summary>
        protected virtual bool TranslateAcceleratorCore(ref MSG msg, ModifierKeys modifiers)
        {

View on GitHub (pinned to 81131a70a4)