dotnet/wpf · error · Win32Exception
new System.ComponentModel.Win32Exception(win32Error)
Error message
new System.ComponentModel.Win32Exception(win32Error)
What it means
CaretElement.Win32CreateCaret throws Win32Exception when the native CreateCaret call fails, wrapping Marshal.GetLastWin32Error(). The Win32 caret (used for text-selection rendering interop) could not be created for the target HWND, typically because the window handle is invalid, the window is being destroyed, or another thread owns the caret.
Solutions
- Ensure the caret is only created/positioned on the UI thread owning the HWND (Dispatcher.Invoke if needed).
- Delay or skip caret creation when the window/HwndSource handle is invalid or the window is closing.
- Catch Win32Exception around caret operations and retry on the next blink/render cycle rather than crashing.
- Check window handle lifetime (HwndSource.IsDisposed, IntPtr.Zero checks) before caret operations.
Example fix
// before
// inside caret update: throws Win32Exception when HWND invalid
win32CreateCaret(...);
// after
try {
win32CreateCaret(...);
} catch (System.ComponentModel.Win32Exception) {
// handle gone or thread mismatch; retry on next layout/blink cycle
Dispatcher.BeginInvoke(DispatcherPriority.Render, new Action(UpdateCaret));
} Defensive patterns
Strategy: retry
Validate before calling
var source = HwndSource.FromVisual(textBox) as HwndSource; bool canCreate = source != null && !source.IsDisposed && source.Handle != IntPtr.Zero;
Type guard
bool HasLiveHandle(HwndSource s) => s != null && !s.IsDisposed && s.Handle != IntPtr.Zero;
Try / catch
try { /* caret creation path */ } catch (Win32Exception ex) { Dispatcher.BeginInvoke(() => RetryCaretCreation()); /* log ex.ErrorCode */ } Prevention
- Only create/position the Win32 caret on the thread owning the HWND
- Check HwndSource liveness before caret operations
- Defer caret work when the window is closing (Unloaded/Closing)
- Swallow-and-retry transient Win32 caret failures on the next blink cycle
When it happens
Trigger: SetBlinking/Win32SetCaretPos triggering caret (re)creation against an HWND that is invalid, already destroyed, or belongs to another thread; a window being closed while the text editor still tries to show the caret; resource exhaustion preventing caret creation.
Common situations: Closing or hiding a window during a focus change while the caret blink timer fires; hosting WPF content in HwndSource with rapid handle recreation; multi-threaded UI access to the caret; terminal-service/RDP sessions where caret creation intermittently fails.
Related errors
- SR.ChildWindowNotCreated
- SR.PeoplePickerErrorConditionFromOpenQueryWindow (formatted…
- The operation completed successfully.
- Win32Exception (native SystemParametersInfo failure…
- Win32Exception (native SystemParametersInfo failure…
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/fd1a391cd6a4b601.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Documents/CaretElement.cs:999
// Specified height with the current caret height will sync the win32 caret which
// Win32 Magnifer rely on the caret height to scroll their window.
NativeMethods.BitmapHandle bitmap = UnsafeNativeMethods.CreateBitmap(/*width*/ 1, /*height*/ ConvertToInt32(deviceHeight), /*panels*/ 1, /*bitsPerPixel*/ 1, /*bits*/ null);
// Specified width and height as zero since they will be ignored by setting the bitmap.
bool returnValue = UnsafeNativeMethods.CreateCaret(new HandleRef(null, hwnd), bitmap, /*width*/ 0, /*height*/ 0);
int win32Error = Marshal.GetLastWin32Error();
if (returnValue)
{
_win32Caret = true;
_win32Height = _height;
}
else
{
_win32Caret = false;
// Throw the Win32 exception with GetLastWin32Error.
throw new System.ComponentModel.Win32Exception(win32Error);
}
}
}
}
// Destroy Win32 caret if we create it with checking Win32 error.
private void Win32DestroyCaret()
{
if (!_isSelectionActive)
{
// We do not want to interfere with Win32 caret
// if this Adorner isnt representing active selection
return;
}
// We only destroy the caret what we created a Win32 caret.
if (_win32Caret)
{View on GitHub (pinned to 81131a70a4)