Documentation only. Nothing here was fixed or changed in source. Each item is labeled Observed (verifiable in code) or Potential (inferred, unverified).
-
Duplicated cleanup in destructor and finalizer.
MyForm::~MyForm(lines 26–74) andMyForm::!MyForm(lines 76–106) both perform camera disable/enable (DisableTargetCameraHardware/EnableTargetCameraHardware) and free the same handles/native memory (hWakeupEvent,hLidNotification,hButtonNotification,cachedCameras,selectedInstanceId,hAppMutex). In C++/CLI, the destructor calls the finalizer, so on a deterministic dispose both run. This can cause the camera toggle to execute twice at shutdown. Impact: an extra (idempotent) enable/disable and double handle closing; theCloseHandleon an already-closed handle is guarded by the member being set toNULLonly in the destructor, while the finalizer also closes — potential double-close is mitigated only if the runtime skips the finalizer after the destructor. Not fixed. -
TryEnterHardwareToggleCooldown/RecordHardwareToggleTimeare effectively unused in the main flow.SetCameraHardwareStateVerifiedcallsRecordHardwareToggleTime(stampsg_lastHardwareToggleTick), butTryEnterHardwareToggleCooldownis never invoked anywhere in the current code. TheCOOLDOWN_MILLISECONDS/lastToggleTimestaticmembers are also unused for control flow (logging/UI only). This is a dormant code path inherited from v2.0. Not fixed. -
cameraStateInitialized,restartQueuedByMismatch,lastCameraToggleTickare declared but not meaningfully used. Legacy/placeholder members retained from the original. Not fixed. -
Globals changed from
statictoextern. In the original monolith the fourg_last*variables were file-static(single TU). To support multiple.cpptranslation units they are nowexterninMyForm.hand defined once inMyForm_Camera.cpp. Behavior is preserved (single authoritative instance), but the change is a structural requirement of the extraction, not a behavioral one. By design. -
system("taskkill /F /IM ...")in the ghost-reset path. Shells out to kill all instances beforeApplication::Restart(). Covers the legacyWindows_Hello_Fix_v2_0.exeplus both v2.1 payloads (_x86/_x64) so an arch switch cannot leave a stale process. Works but is a heavy-handed self-termination; inherited from v2.0. Not fixed. -
Build warnings:
warning C4793forTryEnterHardwareToggleCooldownandRecordHardwareToggleTime("function compiled as native: found an intrinsic not supported in managed code"). These are expected for interlocked/GetTickCount64usage inside a/clrcompile on both Release|Win32 and Release|x64 and match the original baseline. The 64-bit tick uses the_InterlockedCompareExchange64compiler intrinsic (single code path on x86/x64) because the SDK excludes theInterlocked*64API aliases from managed x86 code. No change. -
RecoveryLoopFailsafeis disarmed by hide-to-background and never re-armed.OnOwnerClosingruns on everyFormClosing— includingUserClosing, whichMyForm_FormClosingcancels (hide-to-background, the normal "close" path). The form lives on but the fast verifier stays disarmed for the rest of the process lifetime, becauseLoadnever fires again. Traceable in source (main.cpp:54subscription +MyForm_UI.cpp:6-8cancel). After the user closes the window once, onlyCameraFailsafe(90 s poll) remains. Not fixed (documentation pass only). -
CameraFailsafeis timer-only;docs/Plan.md §3still describes a 60 s poll +CM_Register_Notificationlayer. The current source polls every 90 s (kIdleIntervalMs = 90000,CameraFailsafe.h:39) and contains no PnP notification registration;MyForm_Events.cpphas no correspondingWM_APP+0x20handler. A disable inside the 45 s startup grace, or between 90 s polls, waits for the next poll + 10 s confirmation (100 s worst).RecoveryLoopFailsafe(5 s / 30 s / 5 s) exists to cover this gap. Not fixed — recorded so the plan is not mistaken for the implementation. -
Two watchdogs keep independent cooldown/failure state.
CameraFailsafeandRecoveryLoopFailsafeeach hold their ownconsecutiveFailures/lastRecoveryTick/stateand never call each other. Simultaneous detection resolves to two back-to-back enable-onlyRecover(false)calls — idempotent, no disable involved — butdiagnostic.logwill show interleavedFailsafe_*andRecoveryLoop_*lines for the same incident. By design (no shared mutable state = no cross-watchdog race). -
RequestRecoveryCheck(reason)ignores itsreasonparameter. All call sites passL"StartupVerification"; the label is reserved for future event sources (PnP, resume). Harmless. Not fixed. -
CameraFailsafe::Disarmguard is nearly vacuous.if (!isArmed && pollTimer == nullptr && verifyTimer == nullptr) return;only returns early when fully unarmed and both timers are null (i.e. the ctor never ran). Post-construction it always proceeds to stop timers — which is exactly the safe behavior, just expressed oddly. Not fixed.
-
Possible race on
selectedInstanceId/cachedCameras. These are raw pointers accessed on the UI thread and the (background) wake thread only touches UI, so no live race in practice; but there is no lock protecting thestd::wstring*/std::vector*from concurrent access if a future change calls camera members off-thread. Currently safe. -
isAlreadyDisabledis astaticinsideWndProc. It persists for the lifetime of the process and is shared across all messages. If a suspend event is missed (no resume received), the flag could remaintrueand suppress a later legitimate disable. Observed design; only a concern if Windows omits the resume message (unverified). -
Debounce windows are wall-clock
GetTickCount64based. A system clock jump (rare) could cause a missed or duplicated event. Inherited from v2.0. -
Config file has no locking.
SaveConfigStatetruncates and rewrites; concurrent writes (e.g., toggle + Load) are not guarded beyond the single-threaded UI model. Potential only under unexpected multithreading.
- The root
MyForm.hshim is intentional and does not change behavior;main.cppstill includes the same logical header. - Multiple
.cppfiles definingMyFormmember functions is valid C++/CLI; there is exactly one class definition (inMyForm.h) and many out-of-line member definitions. - No controller classes were introduced;
MyFormremains the sole state owner (per the extraction rules). - The two watchdogs are not a "second camera driver": neither
src/watchdogfile containsSetupDi*/CM_*device-state calls, neither parsesconfig.txt, and neither mutatesMyFormstate — all hardware changes flow throughsrc/core/MyForm_Camera.cpp. CameraFailsafedoubling its poll interval to 180 s afterMaxRetries, andRecoveryLoopFailsafekeeping 30 s, is intentional asymmetry (long-term backoff vs persistent fast backup), not a bug.