dotnet/wpf · error · InvalidOperationException
ERROR_NOACCESS (998) / ERROR_ACCESS_DENIED (5)
ERROR_NOACCESS (998) / ERROR_ACCESS_DENIED (5)
Error message
InvalidOperationException
What it means
The Win32 error mapper throws InvalidOperationException for ERROR_NOACCESS (998, invalid access to a memory location) and ERROR_ACCESS_DENIED (5). The native call was refused — either a bad memory access or insufficient rights — and the library maps this to the standard 'operation cannot be performed' exception rather than a UIA-specific one.
Solutions
- Run the automation client at the same or higher elevation/integrity level as the target app
- Avoid automating secure UI (UAC consent, elevated windows) — UIPI blocks it by design
- Catch InvalidOperationException and treat the target as blocked rather than broken
- If 998 appears in your own P/Invoke, check buffer sizes and marshaling before blaming the target
Example fix
// before
var info = GetWindowInfo(hwnd); // error 5/998 -> InvalidOperationException
// after
try
{
var info = GetWindowInfo(hwnd);
}
catch (InvalidOperationException)
{
// access denied / invalid access: target likely elevated; require matching elevation
info = null;
} Defensive patterns
Strategy: validation
Validate before calling
// Compare integrity levels before automating a window: bool canAccess = GetProcessIntegrityLevel(targetPid) <= GetProcessIntegrityLevel(currentPid);
Try / catch
try { QueryWindow(hwnd); } catch (InvalidOperationException) { ElevateOrSkip(target); } Prevention
- Run the automation client with elevation matching or exceeding the target app
- Never attempt to automate UAC consent or other secure desktop UI
- Check process integrity levels before cross-process window queries
- When running from a service/session, verify you target windows in your own session
When it happens
Trigger: Win32 calls made by UIA client proxies failing with last error 998 or 5 — accessing a window of an elevated/other-session process, or a native API writing to an invalid buffer.
Common situations: Automating an app running elevated (admin) from a non-elevated automation process; UIPI/mandatory-integrity-level blocks on UAC prompts; cross-session (RDP/service) access attempts.
Understand the failure class
Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.
Related errors
- ERROR_INVALID_MENU_HANDLE..ERROR_WINDOW_OF_OTHER_THREAD (1401-1408)
- ERROR_INVALID_PARAMETER (87)
- ERROR_NOT_ENOUGH_MEMORY (8) / ERROR_OUTOFMEMORY (14)
- ERROR_SEM_TIMEOUT (121) / WAIT_TIMEOUT (258) / ERROR_SERVICE_REQUEST_TIMEOUT (1053) / ERROR_TIMEOUT (1460)
- ArgumentOutOfRangeException
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/aa6068e8434f59a9.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/UIAutomation/UIAutomationClientSideProviders/MS/Internal/AutomationProxies/Misc.cs:1695
case 1404: // 1404 ERROR_INVALID_HOOK_HANDLE Invalid hook handle.
case 1405: // 1405 ERROR_INVALID_DWP_HANDLE Invalid handle to a multiple-window position structure.
case 1406: // 1406 ERROR_TLW_WITH_WSCHILD Cannot create a top-level child window.
case 1407: // 1407 ERROR_CANNOT_FIND_WND_CLASS Cannot find window class.
case 1408: // 1408 ERROR_WINDOW_OF_OTHER_THREAD Invalid window; it belongs to other thread.
throw new ElementNotAvailableException();
// We're getting this in AMD64 when calling RealGetWindowClass; adding this code
// to allow the DRTs to pass while we continue investigation.
case 87: // 87 ERROR_INVALID_PARAMETER
throw new ElementNotAvailableException();
case 8: // 8 ERROR_NOT_ENOUGH_MEMORY Not enough storage is available to process this command.
case 14: // 14 ERROR_OUTOFMEMORY Not enough storage is available to complete this operation.
throw new OutOfMemoryException();
case 998: // 998 ERROR_NOACCESS Invalid access to memory location.
case 5: // 5 ERROR_ACCESS_DENIED
throw new InvalidOperationException();
case 121: // 121 ERROR_SEM_TIMEOUT The semaphore timeout period has expired.
case 258: // 258 WAIT_TIMEOUT The wait operation timed out.
case 1053: // 1053 ERROR_SERVICE_REQUEST_TIMEOUT The service did not respond to the start or control request in a timely fashion.
case 1460: // 1460 ERROR_TIMEOUT This operation returned because the timeout period expired.
throw new TimeoutException();
default:
// Not sure how to map the reset of the error codes so throw generic Win32Exception.
throw new Win32Exception(errorCode);
}
}
internal static bool UnhookWinEvent(IntPtr winEventHook)
{
// There is no indication in the Windows SDK documentation that UnhookWinEvent()
// will set an error to be retrieved with GetLastError
return UnsafeNativeMethods.UnhookWinEvent(winEventHook);View on GitHub (pinned to 81131a70a4)