# Windows Hello Fix v2.1 — Architecture
> Documentation-only. Describes the **current** source under `src/core/` + `src/watchdog/` + `main.cpp`. No code was modified.
## Reference implementation relationship
```
reference/release-v2.0/MyForm.h (monolith, known-good camera truth)
│ mechanical extraction
▼
src/core/MyForm.h declaration only (class, struct, globals `extern`)
src/core/MyForm_Camera.cpp native camera pipeline + Disable/Enable/Restore members
src/core/MyForm_Config.cpp config + diagnostic logging + target resolution
src/core/MyForm_Core.cpp ctor / dtor / finalizer / InitializeComponent / MyForm_Load + failsafe accessors
src/core/MyForm_Events.cpp WndProc (session / power / shutdown)
src/core/MyForm_System.cpp command parsing + wake listener
src/core/MyForm_UI.cpp FormClosing + btnToggle_Click
│ later addition (failsafe work, outside src/core)
▼
src/watchdog/CameraFailsafe.* long-term observe/recover (owned by MyForm)
src/watchdog/RecoveryLoopFailsafe.* fast startup/poll/retry (owned by main.cpp)
main.cpp entry + hidden launch + RecoveryLoopFailsafe wiring
```
The extraction kept **`MyForm` as the single, central state owner**. No `ApplicationController`, `CameraController`, `EventController`, or `RecoveryController` was introduced. Only member-function *bodies* moved into separate translation units; the class, its members, its lifetime, and its behavioral authority are unchanged from `release-v2.0/MyForm.h`.
The root `MyForm.h` is a 3-line shim:
```cpp
#pragma once
#include "src/core/MyForm.h"
```
This preserves the original `#include "MyForm.h"` path used by `main.cpp` without altering it.
## High-level architecture
```mermaid
flowchart TD
A[main.cpp] --> B[MyForm]
A --> R[RecoveryLoopFailsafe
fast verifier]
B --> C[MyForm_Core.cpp
ctor/dtor/Load]
B --> D[MyForm_Camera.cpp
hardware pipeline]
B --> E[MyForm_Config.cpp
config + logging]
B --> F[MyForm_Events.cpp
WndProc]
B --> G[MyForm_System.cpp
commands + wake]
B --> H[MyForm_UI.cpp
UI handlers]
B --> W[CameraFailsafe
long-term failsafe]
C -->|startup| D
C -->|startup| E
C -->|startup| G
C -->|arm| W
F -->|lock/sleep| D
F -->|unlock/resume| D
H -->|stop| D
G -->|wake signal| B
W -->|observe| D
W -->|recover enable-only| D
R -->|observe| D
R -->|recover enable-only| D
```
> **Authority rule (load-bearing):** `D` (`MyForm_Camera.cpp`) is the only box that changes device state. `W` and `R` observe via `GetCameraHardwareDisabledState` and recover via `RecoverCameraHardware(target, false)` + `VerifyCameraHardwareState` — they contain no `SetupDi*`/`CM_*` device-state calls.
## Runtime lifecycle
```mermaid
flowchart TD
A[Process start] --> B[main.cpp: MyForm form]
B --> B2[main.cpp: wire RecoveryLoopFailsafe
Load → Arm, FormClosing → Disarm]
B2 --> C[Application::Run]
C --> D[MyForm ctor → InitializeComponent]
D --> E[MyForm_Load]
E --> F[Single-instance mutex]
F --> G[Restore camera]
G --> H[Register power + WTS]
H --> H2[Arm CameraFailsafe + fire Load → RecoveryLoop Arm]
H2 --> I[Populate dropdown / auto-start]
I --> J[Start wake listener thread]
J --> K[Steady state: monitoring]
K --> L[Lock / Sleep → disable camera]
K --> M[Unlock / Resume → enable camera]
K --> N[Watchdog: unexpected Disabled → enable-only recover]
K --> O[Shutdown → isSystemEnding → disarm watchdogs → dtor]
```
## State ownership
| State | Owner |
|---|---|
| `isMonitoring` | `MyForm` |
| `isBackgroundMode`, `isSystemEnding` | `MyForm` |
| `cachedCameras`, `selectedInstanceId` (raw pointers) | `MyForm` (manual new/delete) |
| `cameraExpectedDisabled`, `cameraStateInitialized`, `restartQueuedByMismatch` | `MyForm` |
| `hAppMutex`, `hWakeupEvent` | `MyForm` |
| `hLidNotification`, `hButtonNotification` | `MyForm` |
| `backgroundWorker`, `keepListening` | `MyForm` |
| `deviceDrop`, `btnToggle`, `lblTitle`, `lblStatus`, `components` | `MyForm` (WinForms) |
| `diagnosticLogSync` | `MyForm` |
| `cameraFailsafe` (owned watchdog) | `MyForm` (created/armed in `MyForm_Load`, disarmed in dtor/finalizer) |
| `recoveryLoop` (fast verifier) | `main.cpp` (wired to `Load`/`FormClosing`, never for command workers) |
| `g_lastHardwareToggleTick`, `g_lastSetupApiError`, `g_lastConfigManagerResult`, `g_lastHardwareToggleStage` | Defined once in `MyForm_Camera.cpp`, `extern` elsewhere (single authoritative instance) |
| `config.txt`, `diagnostic.log` | Filesystem under `%APPDATA%\Windows Hello Fix` |
## Threading model
1. **UI thread** — message pump, `MyForm_Load`, `WndProc`, `btnToggle_Click`, `MyForm_FormClosing`, all camera members when invoked from UI/Load/WndProc, and **both watchdogs** (`CameraFailsafe` poll/verify timers, `RecoveryLoopFailsafe` startup/poll/retry timers — all `System::Windows::Forms::Timer`, all guarded by expected-state checks).
2. **Background wake listener** (`backgroundWorker`, `IsBackground=true`) — runs `ListenForWakeupSignal`, blocks on `WaitForSingleObject(hWakeupEvent)`. Only updates the window via `Invoke`; never touches camera hardware.
No thread pool, no task queue, no async camera operations. This matches the original v2.0 threading model; the watchdogs add timers on the existing pump, not threads.
## Dependency map
```mermaid
flowchart LR
MFH[MyForm.h] --> CAM[MyForm_Camera.cpp]
MFH --> CFG[MyForm_Config.cpp]
MFH --> CORE[MyForm_Core.cpp]
MFH --> EVT[MyForm_Events.cpp]
MFH --> SYS[MyForm_System.cpp]
MFH --> UI[MyForm_UI.cpp]
CAM --> CFG[TrimTrailingChars, ScanSystemCameras used by Config]
CORE --> CAM
CORE --> CFG
CORE --> SYS
EVT --> CAM
EVT --> CFG
UI --> CAM
UI --> CFG
WD1[CameraFailsafe.cpp] --> MFH
WD2[RecoveryLoopFailsafe.cpp] --> MFH
CORE --> WD1
```
`MyForm.h` is the hub; every `.cpp` includes it. `MyForm_Camera.cpp` defines the shared globals and is the only place that calls SetupAPI/CfgMgr to change device state. `MyForm_Core.cpp` is the only core TU that includes a watchdog header (to construct/arm `CameraFailsafe`). `main.cpp` includes `RecoveryLoopFailsafe.h` and owns that instance; the watchdog `.cpp` files include `../core/MyForm.h` for the accessors and native pipeline declarations. Neither watchdog calls the other.
## Camera operation flow (high level)
```mermaid
flowchart TD
A[Event / command / UI] --> B[TryGetTargetCameraInstanceId]
B --> C[GetCameraHardwareDisabledState]
C --> D{Already in target state?}
D -->|yes| Z[Return true]
D -->|no| E[ToggleCameraHardware - SetupAPI]
E --> F[VerifyCameraHardwareState]
F -->|ok| Z
F -->|fail| G[ToggleCameraHardwareCfgMgr]
G --> H[Verify]
H -->|ok| Z
H -->|fail| I{reinitializeOnMismatch?}
I -->|yes| J[Revert toggle + Sleep 250]
J --> E
I -->|no| K[Retry x3 then final attempt]
```
## Windows APIs used (summary)
- **SetupAPI:** `SetupDiGetClassDevs`, `SetupDiEnumDeviceInfo`, `SetupDiGetDeviceInstanceId`, `SetupDiGetDeviceRegistryProperty`, `SetupDiSetClassInstallParams`, `SetupDiCallClassInstaller`, `SetupDiDestroyDeviceInfoList`.
- **Configuration Manager:** `CM_Get_DevNode_Status`, `CM_Enable_DevNode`, `CM_Disable_DevNode`, `CM_Reenumerate_DevNode`.
- **WTS:** `WTSRegisterSessionNotification`, `WTSUnRegisterSessionNotification`.
- **Power:** `RegisterPowerSettingNotification`, `UnregisterPowerSettingNotification`.
- **Sync/IPC:** `CreateMutex`, `OpenEvent`, `CreateEvent`, `SetEvent`, `WaitForSingleObject`, `GetTickCount64`, `Interlocked*`, `Sleep`.
- **Process:** `CreateProcess` family not used directly; `system("taskkill ...")` only in the ghost-reset path.
- **Token:** `OpenProcessToken`, `GetTokenInformation` (elevation/integrity, logging only).
- **WinForms:** `Application::Run`, `MessageBox`, `StreamWriter`/`StreamReader`, `Monitor`, `Invoke`.
See `docs/CAMERA_FLOW.md`, `docs/EVENT_FLOW.md`, `docs/LIFECYCLE.md`, `docs/DEBUGGING.md`, and `docs/KNOWN_ISSUES.md` for detail.