{"record":{"id":"73c75e8e700c963f","repo":"BigPizzaV3/CodexPlusPlus","slug":"setthreaddpiawarenesscontext-failed","errorCode":null,"errorMessage":"SetThreadDpiAwarenessContext failed","messagePattern":"SetThreadDpiAwarenessContext failed","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/codex-plus-core/src/launcher.rs","lineNumber":1396,"sourceCode":"            bytes,\n            content_type.to_string(),\n            \"helper.dream_skin_image_ok\",\n        ),\n        Err(_) => not_found(),\n    }\n}\n\n#[cfg(windows)]\nfn windows_logical_cursor_position() -> anyhow::Result<(i32, i32)> {\n    use windows::Win32::Foundation::POINT;\n    use windows::Win32::UI::HiDpi::{\n        DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED, SetThreadDpiAwarenessContext,\n    };\n    use windows::Win32::UI::WindowsAndMessaging::GetCursorPos;\n\n    let previous = unsafe { SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED) };\n    if previous.0.is_null() {\n        anyhow::bail!(\"SetThreadDpiAwarenessContext failed\");\n    }\n    let mut point = POINT::default();\n    let result = unsafe { GetCursorPos(&mut point) };\n    unsafe {\n        SetThreadDpiAwarenessContext(previous);\n    }\n    result.ok().context(\"GetCursorPos failed\")?;\n    Ok((point.x, point.y))\n}\n\nfn overlay_image_content_type(path: &Path) -> Option<&'static str> {\n    match path\n        .extension()\n        .and_then(|extension| extension.to_str())\n        .map(str::to_ascii_lowercase)\n        .as_deref()\n    {\n        Some(\"png\") => Some(\"image/png\"),","sourceCodeStart":1378,"sourceCodeEnd":1414,"githubUrl":"https://github.com/BigPizzaV3/CodexPlusPlus/blob/1f431ae49b57b3055e0e6845ba6156c6b4232b4d/crates/codex-plus-core/src/launcher.rs#L1378-L1414","documentation":"windows_logical_cursor_position (crates/codex-plus-core/src/launcher.rs:1390, compiled only on Windows) temporarily switches the thread's DPI awareness to DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED before GetCursorPos so coordinates come back in unscaled pixels for the overlay feature. SetThreadDpiAwarenessContext returns null when it fails (its return is the previous context); the code treats null as failure and bails. The API requires Windows 10 1703+, so unsupported older OSes and certain thread/host environments are the practical causes.","triggerScenarios":"Invoking the overlay cursor-position path on Windows where SetThreadDpiAwarenessContext fails: pre-1703 Windows 10 / Windows 7-8.1 (API not exported or returns null), or a thread context in which the DPI-awareness switch is disallowed.","commonSituations":"Running the CodexPlusPlus overlay on an old or LTSC-pre-1703 Windows image; Wine/compatibility layers that stub Win32 DPI APIs; CI runners with stripped Windows shells where per-monitor DPI v2 context handling misbehaves.","solutions":["Run on Windows 10 1703+ where SetThreadDpiAwarenessContext exists and succeeds","Update the windows crate — newer windows-rs versions expose SetThreadDpiAwarenessContextCompat and friends that fall back correctly on older OSes","If you fork the core, degrade gracefully: on null previous context, fall back to GetCursorPos without the DPI switch (coordinates will be scaled, but the call succeeds)","Disable the overlay feature that needs logical cursor positions if the host cannot support DPI queries"],"exampleFix":"// before (crates/codex-plus-core/src/launcher.rs)\nlet previous = unsafe { SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED) };\nif previous.0.is_null() {\n    anyhow::bail!(\"SetThreadDpiAwarenessContext failed\");\n}\n\n// after: tolerate unsupported DPI switch\nlet previous = unsafe { SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED) };\nlet dpi_switched = !previous.0.is_null();\nlet mut point = POINT::default();\nlet result = unsafe { GetCursorPos(&mut point) };\nif dpi_switched { unsafe { SetThreadDpiAwarenessContext(previous); } }","handlingStrategy":"fallback","validationCode":"// Probe support before relying on the overlay path\n#[cfg(windows)]\nfn dpi_awareness_supported() -> bool {\n    use windows::Win32::UI::HiDpi::SetThreadDpiAwarenessContext;\n    use windows::Win32::UI::HiDpi::DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED;\n    let prev = unsafe { SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED) };\n    let ok = !prev.0.is_null();\n    if ok { unsafe { windows::Win32::UI::HiDpi::SetThreadDpiAwarenessContext(prev) }; }\n    ok\n}","typeGuard":null,"tryCatchPattern":"match windows_logical_cursor_position() {\n    Ok(pos) => Some(pos),\n    Err(e) if e.to_string() == \"SetThreadDpiAwarenessContext failed\" => {\n        tracing::warn!(\"DPI query unsupported; overlay uses scaled coordinates or is disabled\");\n        None // degrade to GetCursorPos without DPI switch, or disable overlay\n    }\n    Err(e) => { tracing::error!(%e); None }\n}","preventionTips":["Target Windows 10 1703+ in deployment requirements","Update the windows crate so Compat variants of DPI APIs are available","Feature-gate the overlay on Windows so hosts without DPI support skip it instead of erroring"],"tags":["rust","windows","hidpi","win32-api","cursor","overlay"],"backgroundTag":"win32-api-call-failed","analyzedSha":"1f431ae49b57b3055e0e6845ba6156c6b4232b4d","analyzedAt":"2026-08-16T20:54:18.598Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}