# Phase 5: Native Addon and DWM Capture - Context

**Gathered:** 2026-04-12
**Status:** Ready for planning

<domain>
## Phase Boundary

Build a C++ NAPI addon with DwmGetDxSharedSurface (the same API used by OBS and AHK) that captures any window by HWND and returns a correct PNG buffer. No yellow border, no WM_PRINT. Covers: DWM-01, DWM-02, DWM-03, DWM-04, DWM-05.

This phase delivers a standalone loadable addon with a working `captureWindow(hwnd)` export. Integration into existing targets (WindowTarget, WindowRegionTarget) and fallback logic are Phase 6.

</domain>

<decisions>
## Implementation Decisions

### API Choice (REVISED — user decision 2026-04-12)
- **D-01:** Use DwmGetDxSharedSurface from user32.dll — undocumented but battle-tested API used by OBS and AHK for years. No yellow border, no WM_PRINT, reads directly from DWM composition
- **D-02:** Do NOT pursue WGC (Windows.Graphics.Capture) — yellow border is unacceptable for a diagnostic tool, and the implementation is far more complex (WinRT interop, frame pools, COM events)
- **D-03:** Do NOT pursue DwmRegisterThumbnail — no pixel readback, requires destination window with message pump
- **D-04:** Satisfy success criteria #5 (empirical API validation) by testing DwmGetDxSharedSurface against: (a) GDI app (Notepad), (b) partially occluded window, (c) verifying no flicker/WM_PRINT disruption

### Build Toolchain
- **D-05:** cmake-js for native addon build (CMake handles C++17 and D3D11/DXGI/DWM linking better than node-gyp)
- **D-06:** node-addon-api (C++ wrapper over Node-API) for ergonomic NAPI usage
- **D-07:** Target NAPI version 8 (requires Node.js 18.17+ — project already requires Node 20 LTS)
- **D-08:** Add `cmake-js` and `node-addon-api` as devDependencies; add `node-gyp-build` as dependency (for prebuild loading)

### Crash Isolation
- **D-09:** In-process native addon (no child-process IPC) — simpler architecture, acceptable risk with defensive coding
- **D-10:** Mandatory RAII wrappers for all COM/D3D11/GDI resources (`ComPtr<T>` from `wrl/client.h`)
- **D-11:** `__try/__except` structured exception handling around the capture hot path to convert access violations to NAPI errors instead of process crashes
- **D-12:** Validate HWND with `IsWindow()` before every capture attempt

### PNG Encoding
- **D-13:** Encode PNG in C++ using stb_image_write (single-header, public domain) — avoids 8MB raw BGRA buffer transfer across NAPI boundary
- **D-14:** Perform BGRA-to-RGBA channel swap before PNG encoding (Windows DWM outputs BGRA; PNG expects RGBA)

### Async Architecture
- **D-15:** Use `Napi::AsyncWorker` for capture — D3D11 operations must not block the Node.js event loop
- **D-16:** (Removed — DwmGetDxSharedSurface does not require WinRT/COM initialization per thread)
- **D-17:** D3D11 device created once at addon load, cached as module-level `ComPtr<ID3D11Device>` — reused across all captures
- **D-18:** (Removed — no WGC frame pools needed with DwmGetDxSharedSurface)

### Capture Flow
- **D-19:** Per-capture flow: call DwmGetDxSharedSurface → OpenSharedResource → CopyResource to staging → Map → PNG encode. No session lifecycle management needed
- **D-20:** (Removed — no WaitForSingleObject timeout needed; DwmGetDxSharedSurface is synchronous)

### Yellow Border
- **D-21:** No yellow border — DwmGetDxSharedSurface does not produce one (unlike WGC)
- **D-22:** (Removed — borderless is the default with this API)

### stdout Safety
- **D-23:** Ban `printf` and `std::cout` in all C++ code — use `fprintf(stderr, ...)` only. Define `DWM_LOG` macro writing to stderr. This prevents MCP JSON-RPC stream corruption (v1.0 Pitfall #1 re-emerging from native layer)

### Claude's Discretion
- Native addon directory structure details (file organization within `native/`)
- stb_image_write integration specifics (header inclusion pattern)
- CMakeLists.txt exact configuration beyond the skeleton in ARCHITECTURE.md
- Error message wording for DWM capture failures
- Whether to add `isAvailable()` as a synchronous or async export

</decisions>

<canonical_refs>
## Canonical References

**Downstream agents MUST read these before planning or implementing.**

### Project Research
- `.planning/research/ARCHITECTURE.md` — Full architecture: WGC data flow, component boundaries, native addon structure, CMakeLists skeleton, NAPI export surface, modified files plan
- `.planning/research/PITFALLS.md` — 12 pitfalls with prevention strategies (crash isolation, COM threading, GDI leaks, BGRA format, DPI mismatch, stdout pollution)
- `.planning/research/STACK.md` — Technology choices and alternatives considered
- `.planning/research/SUMMARY.md` — Research synthesis

### Existing Implementation (to understand integration surface)
- `src/capture/targets/capture-target.ts` — CaptureTarget interface (return contract for Phase 6 integration)
- `src/capture/targets/window-target.ts` — Current monitor-crop implementation (will be modified in Phase 6, not Phase 5)
- `src/capture/targets/window-utils.ts` — Current window lookup and capture utilities
- `src/types.ts` — Type definitions

### External References
- [Windows.Graphics.Capture API](https://learn.microsoft.com/en-us/uwp/api/windows.graphics.capture) — Primary API reference
- [IGraphicsCaptureItemInterop::CreateForWindow](https://learn.microsoft.com/en-us/windows/win32/api/windows.graphics.capture.interop/nf-windows-graphics-capture-interop-igraphicscaptureiteminterop-createforwindow) — HWND-based capture creation
- [Win32CaptureSample (robmikh)](https://github.com/robmikh/Win32CaptureSample) — Reference C++ WGC implementation
- [cmake-js](https://github.com/cmake-js/cmake-js) — Build system for native addon
- [node-addon-api](https://github.com/nodejs/node-addon-api) — C++ NAPI wrapper

</canonical_refs>

<code_context>
## Existing Code Insights

### Reusable Assets
- `CaptureTarget` interface: Defines the `capture(): Promise<Buffer>` contract the addon must ultimately satisfy (Phase 6 wires this up)
- `window-utils.ts`: Contains `findWindow()` which resolves HWND from handle/title — the HWND value feeds into the native addon
- `logger.ts`: stderr-only logger for JS-side logging

### Established Patterns
- Async capture: `capture()` returns `Promise<Buffer>` — native addon naturally fits this via `Napi::AsyncWorker`
- PNG buffer output: All existing targets return PNG-encoded buffers — native addon does the same via stb_image_write
- Module-level singletons: Used in server.ts — D3D11 device singleton in the addon follows the same pattern

### Integration Points
- Phase 5 deliverable: `native/build/Release/dwm-capture.node` loadable binary + `src/capture/targets/dwm-capture.ts` TypeScript wrapper
- Phase 6 will wire `dwm-capture.ts` into `window-utils.ts` and modify `WindowTarget.capture()`
- `package.json`: Needs new devDependencies (cmake-js, node-addon-api) and build script

</code_context>

<specifics>
## Specific Ideas

- The Win32CaptureSample (robmikh) GitHub repo is the closest reference implementation — it demonstrates the exact WGC flow needed (CreateForWindow, CreateFreeThreaded, single-frame capture)
- Use `GetGuiResources(GetCurrentProcess(), GR_GDIOBJECTS)` during validation to verify no GDI handle leaks after 100+ captures
- Color validation: capture a Notepad window with known content, decode the PNG, verify red channel is actually red (not blue-shifted from BGRA mismatch)
- The `stb_image_write.h` vendor header is a single file (~50KB) — drop it in `native/vendor/` with no build system complexity

</specifics>

<deferred>
## Deferred Ideas

None — discussion stayed within phase scope

</deferred>

---

*Phase: 05-native-addon-and-dwm-capture*
*Context gathered: 2026-04-12*
