dotnet/wpf · error · OutOfMemoryException
OutOfMemoryException
Error message
OutOfMemoryException
What it means
This GetTextWithinStructureRemoteBitness path allocated a RemoteMemoryBlock (VirtualAllocEx in the target process) to stage the structure before WM_GETTEXT messaging; when the block comes back invalid the allocation failed, and the code throws OutOfMemoryException. Common root causes are the remote process dying or being unable to accept the allocation, or genuine address-space exhaustion (notably in 32-bit targets with fragmented memory).
Solutions
- Retry the text retrieval once — transient allocation failures (e.g. desktop heap pressure) often clear.
- Verify the target process is still alive and responsive; a dying process fails allocations.
- Reduce concurrent UIA clients / remote allocations against the same target, or move to a 64-bit target to relieve address-space pressure.
- Catch OutOfMemoryException (and ElementNotAvailableException) around GetTextWithinStructure and degrade gracefully (skip the property).
Example fix
// before
var text = GetTextWithinStructure(hwnd, cbSize); // throws OutOfMemoryException on alloc failure
// after
try { text = GetTextWithinStructure(hwnd, cbSize); }
catch (Exception ex) when (ex is OutOfMemoryException || ex is ElementNotAvailableException)
{
text = null; // skip or retry after delay
} Defensive patterns
Strategy: retry
Validate before calling
// Check target process health and address-space headroom before the call using var p = Process.GetProcessById(GetPidForHwnd(hwnd)); if (p.HasExited) return null; if (!p.Is64Bit() && remoteAllocPressureHigh) return null; // avoid 32-bit OOM
Type guard
static bool CanAllocateRemotely(IntPtr hwnd, int cb) => IsWindow(hwnd) && !new SafeProcessHandle(hwnd).IsInvalid;
Try / catch
for (int attempt = 0; attempt < 2; attempt++)
{
try { text = GetTextWithinStructure(hwnd, cbSize); break; }
catch (OutOfMemoryException) when (attempt == 0) { Thread.Sleep(250); }
catch (ElementNotAvailableException) { text = null; break; }
} Prevention
- Limit concurrent UIA clients allocating remote buffers in the same target
- Prefer 64-bit target processes to avoid 32-bit address-space exhaustion
- Verify the target process is alive before remote allocation-heavy calls
- Add a bounded single retry with delay for transient allocation failures
When it happens
Trigger: RemoteMemoryBlock allocation of cbSize bytes in the hwnd's process returns an invalid handle (VirtualAllocEx failure) during GetTextWithinStructure — after a valid process handle was opened but before WriteTo/SendMessage.
Common situations: Automating 32-bit applications from a 64-bit client where desktop heap or address space is exhausted; target process terminating between handle open and allocation; many concurrent UIA clients each allocating remote buffers.
Related errors
- ElementNotAvailableException
- ERROR_NOT_ENOUGH_MEMORY (8) / ERROR_OUTOFMEMORY (14)
- ArgumentOutOfRangeException
- E_OUTOFMEMORY
- ElementNotAvailableException
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/c5a95146a8a6b19d.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/UIAutomation/UIAutomationClientSideProviders/MS/Internal/AutomationProxies/CommonXSendMessage.cs:373
}
// Main method. It simply copies an unmamaged buffer to the remote process, sends the message, and then
// copies the remote buffer back to the local unmanaged buffer.
internal static int XSendGetIndex(IntPtr hwnd, int uMsg, IntPtr wParam, IntPtr ptrStructure, int cbSize)
{
using (SafeProcessHandle hProcess = new SafeProcessHandle(hwnd))
{
if (hProcess.IsInvalid)
{
// assume that the hwnd was bad
throw new ElementNotAvailableException();
}
using (RemoteMemoryBlock rmem = new RemoteMemoryBlock(cbSize, hProcess))
{
if (rmem.IsInvalid)
{
throw new OutOfMemoryException();
}
// Copy the struct to the remote process...
rmem.WriteTo(ptrStructure, new IntPtr(cbSize));
// Send the message...
int res = Misc.ProxySendMessageInt(hwnd, uMsg, wParam, rmem.Address);
// Copy returned struct back to local process...
rmem.ReadFrom(ptrStructure, new IntPtr(cbSize));
return res;
}
}
}
//------------------------------------------------------View on GitHub (pinned to 81131a70a4)