{"record":{"id":"c5a95146a8a6b19d","repo":"dotnet/wpf","slug":"outofmemoryexception-commonxsendmessage","errorCode":null,"errorMessage":"OutOfMemoryException","messagePattern":"OutOfMemoryException","errorType":"exception","errorClass":"OutOfMemoryException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.DotNet.Wpf/src/UIAutomation/UIAutomationClientSideProviders/MS/Internal/AutomationProxies/CommonXSendMessage.cs","lineNumber":373,"sourceCode":"        }\n\n        // Main method.  It simply copies an unmamaged buffer to the remote process, sends the message, and then\n        // copies the remote buffer back to the local unmanaged buffer.\n        internal static int XSendGetIndex(IntPtr hwnd, int uMsg, IntPtr wParam, IntPtr ptrStructure, int cbSize)\n        {\n            using (SafeProcessHandle hProcess = new SafeProcessHandle(hwnd))\n            {\n                if (hProcess.IsInvalid)\n                {\n                    // assume that the hwnd was bad\n                    throw new ElementNotAvailableException();\n                }\n\n                using (RemoteMemoryBlock rmem = new RemoteMemoryBlock(cbSize, hProcess))\n                {\n                    if (rmem.IsInvalid)\n                    {\n                        throw new OutOfMemoryException();\n                    }\n\n                    // Copy the struct to the remote process...\n                    rmem.WriteTo(ptrStructure, new IntPtr(cbSize));\n\n                    // Send the message...\n                    int res = Misc.ProxySendMessageInt(hwnd, uMsg, wParam, rmem.Address);\n\n                    // Copy returned struct back to local process...\n                    rmem.ReadFrom(ptrStructure, new IntPtr(cbSize));\n\n                    return res;\n                }\n            }\n        }\n\n\n        //------------------------------------------------------","sourceCodeStart":355,"sourceCodeEnd":391,"githubUrl":"https://github.com/dotnet/wpf/blob/81131a70a4c573cd62748a5c36908fc4d662daa9/src/Microsoft.DotNet.Wpf/src/UIAutomation/UIAutomationClientSideProviders/MS/Internal/AutomationProxies/CommonXSendMessage.cs#L355-L391","documentation":"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).","triggerScenarios":"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.","commonSituations":"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.","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)."],"exampleFix":"// before\nvar text = GetTextWithinStructure(hwnd, cbSize); // throws OutOfMemoryException on alloc failure\n// after\ntry { text = GetTextWithinStructure(hwnd, cbSize); }\ncatch (Exception ex) when (ex is OutOfMemoryException || ex is ElementNotAvailableException)\n{\n    text = null; // skip or retry after delay\n}","handlingStrategy":"retry","validationCode":"// Check target process health and address-space headroom before the call\nusing var p = Process.GetProcessById(GetPidForHwnd(hwnd));\nif (p.HasExited) return null;\nif (!p.Is64Bit() && remoteAllocPressureHigh) return null; // avoid 32-bit OOM","typeGuard":"static bool CanAllocateRemotely(IntPtr hwnd, int cb) => IsWindow(hwnd) && !new SafeProcessHandle(hwnd).IsInvalid;","tryCatchPattern":"for (int attempt = 0; attempt < 2; attempt++)\n{\n    try { text = GetTextWithinStructure(hwnd, cbSize); break; }\n    catch (OutOfMemoryException) when (attempt == 0) { Thread.Sleep(250); }\n    catch (ElementNotAvailableException) { text = null; break; }\n}","preventionTips":["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"],"tags":["ui-automation","out-of-memory","cross-process","remote-memory"],"backgroundTag":"out-of-memory","analyzedSha":"81131a70a4c573cd62748a5c36908fc4d662daa9","analyzedAt":"2026-09-14T10:12:48.479Z","contentChangedAt":"2026-09-14T10:12:48.479Z","schemaVersion":2},"datasetVersion":"2026-09-21T21:30:21.729Z"}