dotnet/wpf · error · Win32Exception

Win32Exception(Marshal.GetLastWin32Error())

Error message

Win32Exception(Marshal.GetLastWin32Error())

What it means

After sending WM_UPDATEUISTATE (to hide accelerators/focus cues) via SendMessage, the code treats a non-zero return as failure and throws a Win32Exception built from Marshal.GetLastWin32Error(). This surfaces OS-level failures while WindowsFormsHost configures the WinForms child control's UI state.

Solutions

  1. Check that the WindowsFormsHost and its Child handles are alive (IsHandleCreated) before focus/keyboard operations.
  2. Wrap interop keyboard calls in try-catch for Win32Exception and ignore during teardown.
  3. Verify the child control is not disposed while the host updates UI state.
  4. If reproducible, ensure the control's Handle is created (force Handle access) before hosting operations.

Example fix

// before
host.Focus(); // may hit disposed handle -> Win32Exception
// after
if (host.Child != null && host.Child.IsHandleCreated)
{
    try { host.Focus(); }
    catch (System.ComponentModel.Win32Exception) { /* handle gone during teardown */ }
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (host.Child == null || !host.Child.IsHandleCreated || host.Child.IsDisposed)
    return; // skip UI-state update

Type guard

bool HasLiveHandle(System.Windows.Forms.Control c) => c != null && c.IsHandleCreated && !c.IsDisposed;

Try / catch

try { SendUiStateUpdate(); }
catch (Win32Exception ex) { log.Warn("WM_UPDATEUISTATE failed (handle may be gone)", ex); }

Prevention

When it happens

Trigger: The control's handle is invalid/destroyed when the message is sent (host disposed during teardown or before handle creation), or the target window fails to process WM_UPDATEUISTATE, returning non-zero.

Common situations: Closing or hiding a WPF window containing a WindowsFormsHost during keyboard focus transitions; handle recreation on theme/display changes; races during window close.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/WindowsFormsIntegration/System/Windows/Integration/WindowsFormsHost.cs:967

            // (sometimes cues were shown, sometimes not.  This forces it to a known state.
            UpdateUIState(NativeMethods.UIS_SET);
        }

        /// <summary>
        ///     For keyboard interop
        ///     Ensure the visual shortcut key cues on controls are in the same visual
        ///     state that we expect. This is a workaround for odd Windows API.
        /// </summary>
        internal void UpdateUIState(int uiAction)
        {
            Debug.Assert(uiAction == NativeMethods.UIS_INITIALIZE || uiAction == NativeMethods.UIS_SET, "Unexpected uiAction");
            int toSet = NativeMethods.UISF_HIDEACCEL | NativeMethods.UISF_HIDEFOCUS;
            if (UnsafeNativeMethods.SendMessage(new HandleRef(this, this.Handle),
                 NativeMethods.WM_UPDATEUISTATE,
                 (IntPtr)(uiAction | (toSet << 16)),
                 IntPtr.Zero) != IntPtr.Zero)
            {
                throw new Win32Exception(Marshal.GetLastWin32Error());
            }
        }

        // CSS Added for keyboard interop
        // Catch WM_CHAR messages which weren't handled by Avalon
        //  (including mnemonics which were typed without the "Alt" key)
        private void InputManager_PostProcessInput(object sender, SWI.ProcessInputEventArgs e)
        {
            // Should return immediately if this WFH is not in the active Window
            PresentationSource presentationSource = PresentationSource.FromVisual(this._host);
            if (presentationSource == null)
            {
                return;
            }
            Window presentationSourceWindow = presentationSource.RootVisual as Window;

            //CSS This active window check may not work for multiple levels of nesting...
            // RootVisual isn't top level window.  Should we traverse upward through nested levels?

View on GitHub (pinned to 81131a70a4)