BigPizzaV3/CodexPlusPlus · error · anyhow::Error
SetThreadDpiAwarenessContext failed
Error message
SetThreadDpiAwarenessContext failed
What it means
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.
Source
Thrown at crates/codex-plus-core/src/launcher.rs:1396
bytes,
content_type.to_string(),
"helper.dream_skin_image_ok",
),
Err(_) => not_found(),
}
}
#[cfg(windows)]
fn windows_logical_cursor_position() -> anyhow::Result<(i32, i32)> {
use windows::Win32::Foundation::POINT;
use windows::Win32::UI::HiDpi::{
DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED, SetThreadDpiAwarenessContext,
};
use windows::Win32::UI::WindowsAndMessaging::GetCursorPos;
let previous = unsafe { SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED) };
if previous.0.is_null() {
anyhow::bail!("SetThreadDpiAwarenessContext failed");
}
let mut point = POINT::default();
let result = unsafe { GetCursorPos(&mut point) };
unsafe {
SetThreadDpiAwarenessContext(previous);
}
result.ok().context("GetCursorPos failed")?;
Ok((point.x, point.y))
}
fn overlay_image_content_type(path: &Path) -> Option<&'static str> {
match path
.extension()
.and_then(|extension| extension.to_str())
.map(str::to_ascii_lowercase)
.as_deref()
{
Some("png") => Some("image/png"),View on GitHub (pinned to 1f431ae49b)
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
Example fix
// before (crates/codex-plus-core/src/launcher.rs)
let previous = unsafe { SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED) };
if previous.0.is_null() {
anyhow::bail!("SetThreadDpiAwarenessContext failed");
}
// after: tolerate unsupported DPI switch
let previous = unsafe { SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED) };
let dpi_switched = !previous.0.is_null();
let mut point = POINT::default();
let result = unsafe { GetCursorPos(&mut point) };
if dpi_switched { unsafe { SetThreadDpiAwarenessContext(previous); } } Defensive patterns
Strategy: fallback
Validate before calling
// Probe support before relying on the overlay path
#[cfg(windows)]
fn dpi_awareness_supported() -> bool {
use windows::Win32::UI::HiDpi::SetThreadDpiAwarenessContext;
use windows::Win32::UI::HiDpi::DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED;
let prev = unsafe { SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED) };
let ok = !prev.0.is_null();
if ok { unsafe { windows::Win32::UI::HiDpi::SetThreadDpiAwarenessContext(prev) }; }
ok
} Try / catch
match windows_logical_cursor_position() {
Ok(pos) => Some(pos),
Err(e) if e.to_string() == "SetThreadDpiAwarenessContext failed" => {
tracing::warn!("DPI query unsupported; overlay uses scaled coordinates or is disabled");
None // degrade to GetCursorPos without DPI switch, or disable overlay
}
Err(e) => { tracing::error!(%e); None }
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- failed to wait for Windows process id {process_id}
- invalid runtime file path
- missing cached {plugin} plugin for openai-bundled marketplac
- provider sync requires launcher hooks with codex-plus-data i
- Remote Control session recovery requires launcher hooks with
AI-assisted analysis of BigPizzaV3/CodexPlusPlus@1f431ae49b (2026-08-16).
Data as JSON: /api/errors/73c75e8e700c963f.
Report an issue: GitHub.