CNA-GAP-056: A foreign HWND adopted by handle is not subclassed and is absent from windows_, so the Win32 GL, Vulkan, relative-mouse and text-input services refuse it

CNA snapshot 009d40f5  ·  Known Issues › Functional gaps  ·  source links pinned to 009d40f5

✓

Evidence basis: source-verified at the pinned commit; tests exist (not executed for this page). Claims on this page were checked by reading the CNA source at commit 009d40f5; unless a sentence says otherwise, nothing here was built or executed. Nothing on this page was executed unless the Evidence section says so.

AdoptWindowHandle wraps a foreign HWND without subclassing it or adding it to windows_, so it raises no CNA events and FindWindow cannot resolve its id; the WGL, Vulkan, relative-mouse and text-input services then reject it.

Identifier
CNA-GAP-056
Category
Functional gap
Subsystem
Platforms
Status
Open
Verified against
CNA 009d40f5 (009d40f5dd085c4e674d3479675fac84b12b3e0a)
Evidence basis
Source-verified: read at TARGET, not executed
Tests touching this area
Yes: see Current tests
Affected contract
CNA::Platform::Win32::Win32Platform::AdoptWindowHandle(std::uintptr_t) for a window CNA did not create

Expected behaviour

AdoptWindowHandle is documented to wrap a caller-owned window by its legacy handle token and return a non-owning wrapper. GraphicsDevice adopts a host-supplied DeviceWindowHandle through it, so a game that hands CNA a foreign HWND might reasonably expect to render to it.

Actual behaviour at TARGET

For an HWND not already in windows_, AdoptWindowHandle assigns a fresh id and constructs a Win32Window with the adopt tag; that constructor does not subclass the window (only the creating CreateWindowExW path installs StaticWindowProc), so no CNA events flow from it, and the wrapper is tracked in adopted_ but never added to windows_. Every id-based service resolves through FindWindow, which searches only windows_: Win32GlContext::CreateContext and Win32VulkanSurface::CreateSurface, relative-mouse targeting and Win32TextInput::Start all get nullptr and throw “the window id does not name a live window”. Handle-consuming renderers (which read the native handle through TryGetWin32) and the CPU presenter (which takes the Win32Window& directly) still work.

Source locations

Evidence

Checked by reading AdoptWindowHandle, the adopt-tag constructor, FindWindow and the GL/Vulkan/input service lookups at 009d40f5. Not executed (no Windows host). The refusals are clean exceptions, and no CNA contract promises these services on a foreign HWND, so this is a scoped functional gap rather than a broken promise. The Development Win32 page records it.

Focused reproduction

No focused reproduction is known. Nothing has been invented here; the evidence above is what exists.

Current tests

Win32WindowTests.cpp's adoption cases (LegacyTokenRoundTripsThroughAdoption, AdoptedWindowDoesNotDestroy) adopt windows this platform created; none adopts a foreign HWND and then requests a GL context, Vulkan surface, relative mode or text input on it.

Regression test

Create an HWND outside CNA, adopt it by handle, and assert the intended behaviour for each service -- either they work (which requires registering the adopted window and subclassing it) or they refuse with a documented, specific message.

Blast radius

Applications that embed CNA in a foreign HWND and then ask for a GL context, a Vulkan surface, relative-mouse mode or text input on it. CNA-created windows, handle-consuming renderers and the CPU presenter are unaffected.

Workaround

Let CNA create the window (leave DeviceWindowHandle unset), or use a renderer that consumes the native handle directly.

The same subject is explained at several altitudes. These are the neighbouring pages at each one.

Maintainer workflow
Modify a platform backend