REF-035 - Adopt WIL for narrow Windows and COM RAII cleanup¶
Summary¶
Introduce the Windows Implementation Library (WIL) as a setup-managed third-party dependency and use it only where it removes current manual Windows, WinRT, COM, and handle cleanup code.
This is a low-drift hardening item. The goal is not to modernize the app architecture. The goal is to remove cleanup hazards around early returns, error branches, and future edits in leaf Windows API integration code.
Current State¶
The active app still has small but real manual cleanup surfaces:
srchybrid/WindowsToastNotifier.cppCloseHandle(hToken)after token probing.CoInitializeEx/CoUninitializearound shell-link and property-store work.- raw COM
Release()calls forIShellLink,IPropertyStore, andIPersistFile. PropVariantClearafter AppUserModelID property setup.RoInitialize/RoUninitializein the toast-notification activation path.srchybrid/PathHelpers.h- repeated
FindFirstFile/FindClosecleanup in recursive and directory helper code. srchybrid/PartFile.cppCoInitialize/CoUninitializearound shortcut creation.CreateFile/CloseHandlearound part-file allocation behavior.srchybrid/WinInetHandle.h- local
CInternetHandlewrapper overInternetCloseHandle.
None of those surfaces need behavior changes to benefit from RAII. They need the same handles closed on the same paths, with less manual cleanup drift.
Intended Scope¶
- Add WIL through setup/dependency materialization, not as an app-local hidden vendored header.
- Expose the WIL include root through the generated dependency/build props used by the active workspace.
- Convert only narrow leaf cleanup sites first:
WindowsToastNotifier.cppPathHelpers.hPartFile.cpp- optionally
WinInetHandle.h, if replacing the local wrapper does not widen the diff. - Prefer these WIL facilities where they fit directly:
wil::unique_handlefor normalHANDLEownership.wil::unique_anyor a local WIL handle trait forHINTERNETand find handles.wil::com_ptrfor COM interface ownership.wil::unique_prop_variantforPROPVARIANT.wil::scope_exitonly when an API requires paired init/uninit with no better typed wrapper.
Out of Scope¶
- Broad MFC, socket, threading, or UI rewrites.
- Replacing stable local wrappers just for style.
- Changing notification behavior, file allocation behavior, REST behavior, or update-check behavior.
- Introducing exception-based WIL patterns into code paths that are currently status/return-code based.
- Large dependency-topology churn beyond the minimal setup/build include contract.
Implementation Notes¶
- Keep the first code slice small enough to review by resource lifetime: one file or one ownership family at a time.
- Preserve exact return values and logging on failure paths.
- When wrapping init/uninit pairs, ensure the cleanup object is created only after successful initialization.
- Do not hide behavioral fixes inside the RAII conversion. If a leak or missing cleanup branch is discovered, document it in the commit and add a targeted regression where practical.
- If
WinInetHandle.hremains simpler than a WIL custom trait, keep it. WIL is useful here only if it reduces local ownership code or makes call sites safer.
Acceptance Criteria¶
- WIL is tracked as a setup-managed dependency and is discoverable through the generated workspace dependency contract.
- The app builds without app-local hardcoded absolute include paths.
- At least one current manual cleanup surface is converted to typed RAII with no user-visible behavior change.
- Converted code has no remaining duplicate manual cleanup for the same owned resource.
- The diff is limited to ownership/lifetime cleanup plus required build/setup plumbing.
Test Plan¶
- Run setup validation after adding the dependency.
- Build the app through the supported
emulebb-buildentrypoint for the touched platform/configuration. - Build native tests through the supported
emulebb-buildentrypoint. - For
PathHelpers.h, run existing path-helper and long-path tests. - For
PartFile.cpp, run part-file persistence/allocation tests if touched. - For
WinInetHandle.h, run update-check or direct-download seam tests if touched. - For
WindowsToastNotifier.cpp, require at least compile/build coverage; add a manual notification smoke only if the change touches observable toast flow.
Release Value¶
This should be done after active release blockers, but before broad modernization. It is one of the safest library adoptions available because it targets Windows resource lifetime at leaf boundaries and does not require protocol, persistence, or UI behavior changes.