Skip to content

Latest commit

 

History

History
45 lines (25 loc) · 7.11 KB

KNOWN_ISSUES.md

File metadata and controls

45 lines (25 loc) · 7.11 KB

Known Issues & Observations

Documentation only. Nothing here was fixed or changed in source. Each item is labeled Observed (verifiable in code) or Potential (inferred, unverified).

Observed

  1. Duplicated cleanup in destructor and finalizer. MyForm::~MyForm (lines 26–74) and MyForm::!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; the CloseHandle on an already-closed handle is guarded by the member being set to NULL only 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.

  2. TryEnterHardwareToggleCooldown / RecordHardwareToggleTime are effectively unused in the main flow. SetCameraHardwareStateVerified calls RecordHardwareToggleTime (stamps g_lastHardwareToggleTick), but TryEnterHardwareToggleCooldown is never invoked anywhere in the current code. The COOLDOWN_MILLISECONDS/lastToggleTime static members are also unused for control flow (logging/UI only). This is a dormant code path inherited from v2.0. Not fixed.

  3. cameraStateInitialized, restartQueuedByMismatch, lastCameraToggleTick are declared but not meaningfully used. Legacy/placeholder members retained from the original. Not fixed.

  4. Globals changed from static to extern. In the original monolith the four g_last* variables were file-static (single TU). To support multiple .cpp translation units they are now extern in MyForm.h and defined once in MyForm_Camera.cpp. Behavior is preserved (single authoritative instance), but the change is a structural requirement of the extraction, not a behavioral one. By design.

  5. system("taskkill /F /IM ...") in the ghost-reset path. Shells out to kill all instances before Application::Restart(). Covers the legacy Windows_Hello_Fix_v2_0.exe plus 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.

  6. Build warnings: warning C4793 for TryEnterHardwareToggleCooldown and RecordHardwareToggleTime ("function compiled as native: found an intrinsic not supported in managed code"). These are expected for interlocked/GetTickCount64 usage inside a /clr compile on both Release|Win32 and Release|x64 and match the original baseline. The 64-bit tick uses the _InterlockedCompareExchange64 compiler intrinsic (single code path on x86/x64) because the SDK excludes the Interlocked*64 API aliases from managed x86 code. No change.

  7. RecoveryLoopFailsafe is disarmed by hide-to-background and never re-armed. OnOwnerClosing runs on every FormClosing — including UserClosing, which MyForm_FormClosing cancels (hide-to-background, the normal "close" path). The form lives on but the fast verifier stays disarmed for the rest of the process lifetime, because Load never fires again. Traceable in source (main.cpp:54 subscription + MyForm_UI.cpp:6-8 cancel). After the user closes the window once, only CameraFailsafe (90 s poll) remains. Not fixed (documentation pass only).

  8. CameraFailsafe is timer-only; docs/Plan.md §3 still describes a 60 s poll + CM_Register_Notification layer. The current source polls every 90 s (kIdleIntervalMs = 90000, CameraFailsafe.h:39) and contains no PnP notification registration; MyForm_Events.cpp has no corresponding WM_APP+0x20 handler. 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.

  9. Two watchdogs keep independent cooldown/failure state. CameraFailsafe and RecoveryLoopFailsafe each hold their own consecutiveFailures/lastRecoveryTick/state and never call each other. Simultaneous detection resolves to two back-to-back enable-only Recover(false) calls — idempotent, no disable involved — but diagnostic.log will show interleaved Failsafe_* and RecoveryLoop_* lines for the same incident. By design (no shared mutable state = no cross-watchdog race).

  10. RequestRecoveryCheck(reason) ignores its reason parameter. All call sites pass L"StartupVerification"; the label is reserved for future event sources (PnP, resume). Harmless. Not fixed.

  11. CameraFailsafe::Disarm guard 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.

Potential / unverified

  1. 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 the std::wstring*/std::vector* from concurrent access if a future change calls camera members off-thread. Currently safe.

  2. isAlreadyDisabled is a static inside WndProc. 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 remain true and suppress a later legitimate disable. Observed design; only a concern if Windows omits the resume message (unverified).

  3. Debounce windows are wall-clock GetTickCount64 based. A system clock jump (rare) could cause a missed or duplicated event. Inherited from v2.0.

  4. Config file has no locking. SaveConfigState truncates and rewrites; concurrent writes (e.g., toggle + Load) are not guarded beyond the single-threaded UI model. Potential only under unexpected multithreading.

Things that are NOT problems (clarified)

  • The root MyForm.h shim is intentional and does not change behavior; main.cpp still includes the same logical header.
  • Multiple .cpp files defining MyForm member functions is valid C++/CLI; there is exactly one class definition (in MyForm.h) and many out-of-line member definitions.
  • No controller classes were introduced; MyForm remains the sole state owner (per the extraction rules).
  • The two watchdogs are not a "second camera driver": neither src/watchdog file contains SetupDi*/CM_* device-state calls, neither parses config.txt, and neither mutates MyForm state — all hardware changes flow through src/core/MyForm_Camera.cpp.
  • CameraFailsafe doubling its poll interval to 180 s after MaxRetries, and RecoveryLoopFailsafe keeping 30 s, is intentional asymmetry (long-term backoff vs persistent fast backup), not a bug.