andrewmd5/Borderless-Gaming · warning · Win32Exception

Win32Exception

Error message

Win32Exception

What it means

IsProcessElevated throws a Win32Exception when the native OpenProcessToken call fails to open the current process's access token with TOKEN_QUERY access. Win32Exception wraps the last Win32 error code (Marshal.GetLastWin32Error). OpenProcessToken can fail for the current process only in rare conditions such as a corrupted/security-hardened environment, an invalid process handle, or security software blocking token access.

Solutions

  1. Check the Win32Exception.NativeErrorCode for the real failure cause and fix accordingly (e.g. ERROR_ACCESS_DENIED).
  2. Prefer Uac.Elevated (or wrap IsElevated in try/catch) which already swallows this exception and returns false.
  3. Retry once if the call races with process startup/shutdown, since GetCurrentProcess().Handle should always be openable.
  4. If security software blocks token inspection, fall back to Uac.IsRunAsAdmin() (WindowsPrincipal/WindowsBuiltInRole.Administrator) as a heuristic elevation check.

Example fix

// before
return Uac.IsProcessElevated();
// after
bool elevated;
try { elevated = Uac.IsProcessElevated(); }
catch (Win32Exception ex) {
    Trace.WriteLine($"OpenProcessToken failed: {ex.NativeErrorCode}");
    elevated = Uac.IsRunAsAdmin(); // fallback heuristic
}
Defensive patterns

Strategy: try-catch

Validate before calling

// No reliable pre-check: token open for the own process normally always succeeds.
// Guard by checking OS support first:
if (Environment.OSVersion.Version.Major < 6) return; // path never reached
if (!Environment.IsPrivilegedProcess.HasValue) { /* .NET: Environment just probe */ }

Type guard

static bool CanQueryToken()
{
    try
    {
        using var p = System.Diagnostics.Process.GetCurrentProcess();
        return p.Handle != IntPtr.Zero;
    }
    catch { return false; }
}

Try / catch

try
{
    bool elevated = Uac.IsElevated();
}
catch (System.ComponentModel.Win32Exception ex)
{
    Log.Warn($"Token query failed (code {ex.NativeErrorCode}); assuming non-elevated.");
    bool elevated = false;
}

Prevention

When it happens

Trigger: Calling Uac.IsElevated()/Uac.IsProcessElevated() when OpenProcessToken(Process.GetCurrentProcess().Handle, TOKEN_QUERY, out hToken) returns false — e.g. the process handle is invalid (racing process exit), or the security context/AV policy denies opening the own process token.

Common situations: Running under aggressive security/EDR software that hooks advapi32 token APIs; calling the API from an unusual host (service, sandboxed/containersized process) where the pseudo process handle is invalid; a process already terminating when the check runs.

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.


AI-assisted analysis of andrewmd5/Borderless-Gaming@d6a541a64a (2026-09-15). Data as JSON: /api/errors/fea237d307f0e5c7. Report an issue: GitHub.

Appendix: source

Thrown at BorderlessGaming.Logic/Windows/Uac.cs:110

        /// in that, when UAC is turned off, elevation type always returns 
        /// TokenElevationTypeDefault even though the process is elevated (Integrity 
        /// Level == High). In other words, it is not safe to say if the process is 
        /// elevated based on elevation type. Instead, we should use TokenElevation. 
        /// </remarks>
        public static bool IsProcessElevated()
        {
            bool fIsElevated = false;
            SafeTokenHandle hToken = null;
            int cbTokenElevation = 0;
            IntPtr pTokenElevation = IntPtr.Zero;

            try
            {
                // Open the access token of the current process with TOKEN_QUERY.
                if (!NativeMethods.OpenProcessToken(Process.GetCurrentProcess().Handle,
                    NativeMethods.TOKEN_QUERY, out hToken))
                {
                    throw new Win32Exception();
                }

                // Allocate a buffer for the elevation information.
                cbTokenElevation = Marshal.SizeOf(typeof(TOKEN_ELEVATION));
                pTokenElevation = Marshal.AllocHGlobal(cbTokenElevation);
                if (pTokenElevation == IntPtr.Zero)
                {
                    throw new Win32Exception();
                }

                // Retrieve token elevation information.
                if (!NativeMethods.GetTokenInformation(hToken,
                    TOKEN_INFORMATION_CLASS.TokenElevation, pTokenElevation,
                    cbTokenElevation, out cbTokenElevation))
                {
                    // When the process is run on operating systems prior to Windows 
                    // Vista, GetTokenInformation returns false with the error code 
                    // ERROR_INVALID_PARAMETER because TokenElevation is not supported 

View on GitHub (pinned to d6a541a64a)