dotnet/wpf · error · InvalidOperationException
InvalidOperationException
Error message
InvalidOperationException
What it means
CheckForCreateWindowFailure validates the result of CreateWindowEx inside HwndWrapper.WndProc. CreateWindowEx sends WM_CREATE (and WM_NCCREATE) synchronously, so a non-zero result with handled=true during creation means a handler claimed to handle a creation message but returned an invalid result — an internal invariant violation, surfaced as InvalidOperationException.
Solutions
- Do not set handled=true for WM_NCCREATE/WM_CREATE messages in custom WndProc hooks, or return the correct result when doing so
- Fix the hook so it returns 0/continues default processing for creation messages it does not fully handle
- Reproduce under a debugger — the code deliberately breaks there to identify the offending handler
- Check recently added WndProcHook callbacks registered on this HwndWrapper
Example fix
// before
case WM_CREATE:
handled = true;
return 1; // non-zero result with handled -> InvalidOperationException
// after
case WM_CREATE:
return 0; // let default processing continue, handled stays false Defensive patterns
Strategy: try-catch
Try / catch
try { wrapper.Create(); } catch (InvalidOperationException ex) { log("WM_CREATE handler returned invalid result", ex); throw; } Prevention
- Never mark WM_NCCREATE/WM_CREATE handled unless you return the correct non-zero result CreateWindowEx expects
- Return 0 (continue default processing) from hooks for creation messages you don't fully own
- Debug with a debugger attached — the code Debug.Break()s there by design to pinpoint the bad handler
When it happens
Trigger: A WM_NCCREATE/WM_CREATE handler in the WndProc pipeline sets handled=true while returning a non-zero (non-HWND-success) result during CreateWindowEx, most often from a custom WndProcHook or subclass that mishandles creation messages.
Common situations: Custom HwndWrapper subclasses or injected hooks that mark WM_CREATE handled and return wrong values; running under a debugger-detached environment where the Debug.Break path is skipped.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- ArgumentNullException
- InvalidOperationException
- new System.ComponentModel.Win32Exception(win32Error)
- PrintConfig.Provider.BindFail
- ROP data size was not found
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/ef2592af2dd0a339.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/Shared/MS/Win32/HwndWrapper.cs:295
// return our result
return result;
}
private void CheckForCreateWindowFailure( IntPtr result, bool handled )
{
if( ! _isInCreateWindow )
return;
if( IntPtr.Zero != result )
{
System.Diagnostics.Debug.WriteLine("Non-zero WndProc result=" + result);
if( handled )
{
if( System.Diagnostics.Debugger.IsAttached )
System.Diagnostics.Debugger.Break();
else
throw new InvalidOperationException();
}
}
}
/// <summary>
/// Destroys the window with the given handle and class atom and unregisters its window class
/// </summary>
/// <param name="args">A DestrowWindowParams instance</param>
internal static object DestroyWindow(object args)
{
nint handle = ((DestroyWindowArgs)args).Handle;
ushort classAtom = ((DestroyWindowArgs)args).ClassAtom;
Invariant.Assert(handle != 0,
"Attempting to destroy an invalid hwnd");
UnsafeNativeMethods.DestroyWindow(new HandleRef(null, handle));View on GitHub (pinned to 81131a70a4)