···4455## What this is
6677-TaskbarCalculator is a Windows **DeskBand shell extension** — an in-process COM DLL that Explorer loads to embed a small calculator inside the Windows taskbar. It is written in C++ with ATL, targets the Windows shell (`IDeskBand2`), and has no standalone executable: the DLL is registered with the system and hosted by `explorer.exe`.
77+TaskbarCalculator is a small **Windows 11 system-tray calculator**: a standalone C++/Win32
88+executable that lives in the notification area and shows a persistent, always-on-top
99+calculator window driven by keyboard input.
1010+1111+It was **migrated from a DeskBand shell extension** (an in-process COM DLL hosted by the
1212+taskbar), because Windows 11 no longer loads third-party taskbar DeskBands. The design and
1313+implementation history of that migration live in `docs/superpowers/` (spec, plan,
1414+build-env, verification). The `main` branch still holds the original DeskBand baseline;
1515+the migration was done on `feature/win11-tray-calculator`.
816917## Build
10181111-There is no CLI build script; this is a Visual Studio project.
1919+Visual Studio 2022 project (no CLI build script of its own).
12201313-- **Toolchain:** Visual Studio 2017 (`v141` platform toolset), Windows 10 SDK `10.0.17134.0`, ATL linked statically (`UseOfAtl=Static`), Unicode character set.
1414-- **Build in VS:** open `TaskbarCalculator.sln`, pick a configuration (`Debug`/`Release`) and platform (`Win32`/`x64`), and build.
1515-- **Build from command line** (Developer Command Prompt / with MSBuild on PATH):
2121+- **Toolchain:** VS 2022 (`v143`), Windows SDK `10.0.26100.0`, ATL linked statically
2222+ (`UseOfAtl=Static`), Unicode, C++17. Requires C++/WinRT (SDK cppwinrt headers) for the
2323+ start-at-login feature. See `docs/superpowers/BUILD-ENV.md`.
2424+- **Build (x64 is the primary target):**
1625 ```
1717- msbuild TaskbarCalculator.sln /p:Configuration=Release /p:Platform=x64
2626+ msbuild TaskbarCalculator.vcxproj /p:Configuration=Debug /p:Platform=x64
2727+ msbuild TaskbarCalculator.vcxproj /p:Configuration=Release /p:Platform=x64
1828 ```
1919-- Output is `TaskbarCalculator.dll` (a `DynamicLibrary`). The exported entry points are defined in `TaskbarCalculator.def`: `DllRegisterServer`, `DllUnregisterServer`, `DllGetClassObject`, `DllCanUnloadNow`, `DllInstall`.
2020-- The solution also references `..\TaskbarCalculatorSetup\TaskbarCalculatorSetup.vdproj`, a setup project that lives **outside this repository**; it will be missing here.
2929+ Build the **`.vcxproj` directly**, not the `.sln` — the solution references a setup
3030+ project (`..\TaskbarCalculatorSetup\TaskbarCalculatorSetup.vdproj`) that is **not in this
3131+ repo**.
3232+- Output is `x64\<Config>\TaskbarCalculator.exe` (a windowed `Application`; entry point
3333+ `wWinMain` in `App.cpp`).
21342222-There are **no tests** in this repository.
3535+## Test
23362424-## Register / run / debug
3737+The `calc` engine is decoupled from the precompiled header so it builds standalone. Unit
3838+tests use a tiny header-only harness, compiled and run directly with `cl` from an **x64
3939+Native Tools Command Prompt**:
4040+```
4141+tests\build-and-run.cmd
4242+```
4343+Expected: `16/16 passed`. Add engine cases in `tests/CalcTests.cpp` (the `feed()` helper
4444+threads the output string back in as the next input, exactly as the UI does).
25452626-Because there is no `main()`, you exercise the code by registering the DLL and letting Explorer host it:
4646+## Package (MSIX) & run
27472828-- **Register:** `regsvr32 TaskbarCalculator.dll` (or `regsvr32 /i:user` to use `DllInstall` with per-user registration via `AtlSetPerUserRegistration`).
2929-- **Unregister:** `regsvr32 /u TaskbarCalculator.dll`.
3030-- After registering, add the band from the taskbar's toolbars context menu. Explorer caches loaded DLLs, so you typically must restart `explorer.exe` between rebuilds.
3131-- Registration is driven by `TaskbarCalculator.rgs` under the CLSID `{1B1E01F4-6B08-44F9-A1E8-40BC40B55578}` with `ThreadingModel = Apartment`.
4848+- **Run (dev):** launch `x64\Debug\TaskbarCalculator.exe`. It adds a tray icon; left-click
4949+ toggles the window, right-click opens the menu (Show/Hide, Start at login, About, Exit).
5050+- **Start-at-login** uses the MSIX `windows.startupTask` API, so it only works when the app
5151+ is **packaged/installed**; unpackaged it reports `Unavailable` and the menu item is grayed.
5252+- **Package:** from `Packaging\`, run `MakeAssets.ps1` (once), `MakeCert.ps1` (once), then
5353+ `BuildMsix.ps1` → `Packaging\TaskbarCalculator.msix`. Install steps (trust the dev cert +
5454+ `Add-AppxPackage`) are documented in `docs/superpowers/VERIFICATION.md` and require an
5555+ elevated shell.
32563357## Architecture
34583535-The code splits cleanly into three layers:
5959+Three layers, plus small support modules:
36603737-1. **COM/shell integration — `CCalculatorDeskBand`** (`CalculatorDeskBand.cpp/.h`)
3838- The ATL coclass Explorer instantiates. It implements the DeskBand contract: `IDeskBand2`, `IObjectWithSite`, `IDockingWindow`/`IOleWindow`, `IInputObject`, `IContextMenu`, and `IPersistStreamInit`. Key flow:
3939- - `SetSite` receives the taskbar's site, gets the parent HWND, and creates the child `CCalculatorWindow`.
4040- - `GetBandInfo` reports sizing (`CalcIdealSize`) and title back to the shell.
4141- - `IContextMenu` adds a single "Settings" item that currently just opens the About dialog (`AboutDialogProc` / `AboutDialog.cpp`).
4242- - `IPersistStreamInit` load/save is stubbed out (the commented-out `PROP_MAP` and date-format code are leftovers).
6161+1. **App shell — `App.cpp`**
6262+ `wWinMain` initializes WinRT (`init_apartment`) and common controls, enforces a
6363+ **single-instance** guard (named mutex; a second launch signals the first via
6464+ `IDM_SHOWHIDE` and exits), creates a **hidden top-level owner window** (`WS_EX_TOOLWINDOW`)
6565+ that owns the tray icon, then creates the calculator window and runs the message loop.
6666+ `OwnerWndProc` routes the tray callback (`WM_TRAY_CALLBACK`) and menu commands, re-adds the
6767+ tray icon on the `TaskbarCreated` broadcast (survives Explorer restarts), and opens the
6868+ About dialog (`AboutDialogProc` in `AboutDialog.cpp`, a raw-Win32 dialog over `IDD_ABOUT`).
43694444-2. **Window/host + input + formatting — `CCalculatorWindow`** (`CalculatorWindow.cpp/.h`)
4545- A `CWindowImpl` that owns a child Win32 `EDIT` control. It:
4646- - Subclasses the edit control (`WndEditProc`) to intercept `WM_KEYDOWN`/`WM_CHAR` and translate keystrokes into calculator command chars (see the `CALC_*` defines in `Calculator.h`). `OnEditKeyDown` handles numpad/VK keys; `OnEditChar` handles typed characters (including hex `A`–`F`, `q`=sqrt, `p`=negate, `r`=Euro, `l`=Lire, `x`/`i`=hex/dec base toggle).
4747- - Owns the `calc` engine instance and pushes each command into it.
4848- - Handles painting via a double-buffered, themed background (`CVisualStyle`), and repositions the edit control on `WM_PAINT`.
4949- - `ReadRegionalSettings()` reads `HKCU\Control Panel\International` (`sDecimal`, `sThousand`, `iDigits`) to drive display formatting and engine precision; re-read on focus and `WM_SETTINGCHANGE`.
5050- - `FormatString()` inserts thousands/decimal separators for display (decimal base only); the engine always works on an unformatted string.
7070+2. **Calculator window + input + formatting — `CCalculatorWindow`** (`CalculatorWindow.cpp/.h`)
7171+ An ATL `CWindowImpl` top-level tool window (`WS_POPUP`, `WS_EX_TOPMOST | WS_EX_TOOLWINDOW`)
7272+ that owns a child `EDIT` control. `CreateStandalone` builds it hidden; `ToggleVisible`
7373+ shows/hides it (re-asserting top-most); `PlaceInitial` restores the saved position or, on
7474+ first run, anchors bottom-right above the tray via `SHAppBarMessage`. It subclasses the
7575+ edit control (`WndEditProc`) to translate `WM_KEYDOWN`/`WM_CHAR` into `CALC_*` command
7676+ chars (`OnEditKeyDown`/`OnEditChar`), pushes them into `calc`, and paints a themed,
7777+ double-buffered background (`CVisualStyle`). `WM_CLOSE` hides to tray (does not exit);
7878+ `WM_LBUTTONDOWN` drags the window; `WM_EXITSIZEMOVE` persists the position.
7979+ `ReadRegionalSettings` reads `HKCU\Control Panel\International` (`sDecimal`, `sThousand`,
8080+ `iDigits`); `FormatString` inserts separators for display while the engine stays unformatted.
518152823. **Calculation engine — `calc`** (`Calculator.cpp`, `Calculator.h`)
5353- A UI-independent finite state machine. `change_state(newChar, oldString, newString)` is the single entry point: it takes the current display string plus a command char and produces the next string. States: `init / first_oper / operation / second_oper / result / error`. Supports the four operations, sqrt, percent, sign inversion, decimal⇔hex base switching, and a hardcoded Italian Lire⇔Euro conversion (`CHANGE_LIRE_EURO = 1936.27`). Errors surface as the literal strings `ERR_STR_OVERFLOW` / `ERR_STR_DIVBYZERO`, which the window layer detects and displays without formatting.
8383+ A UI-independent finite state machine. `change_state(newChar, oldString, newString)` is
8484+ the single entry point. States: `init / first_oper / operation / second_oper / result /
8585+ error`. **Decimal-only**: four operations, sqrt, percent, sign inversion, reciprocal
8686+ (1/x), `000`, reset. Errors surface as `ERR_STR_OVERFLOW` / `ERR_STR_DIVBYZERO`, which the
8787+ window shows unformatted. (The old hex/base mode and Italian Lire⇔Euro conversion were
8888+ removed in the migration.)
54895555-`VisualStyle.cpp/.h` provides an abstract `CVisualStyle` with `CVisualStyle::Create()` returning a classic-vs-themed implementation; it supplies the font and the background-draw routine. `Utils.cpp/.h`, `stdafx.h` (precompiled header, ATL + shell includes), `DllMain.cpp` (`_AtlModule` + DLL exports), and the `.rc`/`resource.h`/`.idl`/`.rgs` files round out the project.
5656-5757-## Naming gotchas
5858-5959-The project began life as a *calendar* DeskBand, and some identifiers still carry the old name even though the class is the calculator: notably the CLSID symbol `CLSID_CalendarDeskBand` (in `Guids.h`) and the module class `CCalculatorDeskBandModule`. These are intentional/legacy — don't "fix" them to match without checking every reference, since the `.rgs`, IDL, and `OBJECT_ENTRY_AUTO` all key off `CLSID_CalendarDeskBand`.
9090+Support modules: **`Settings`** (`HKCU\Software\TaskbarCalculator` — window position &
9191+visibility as `REG_DWORD`), **`StartupManager`** (WinRT `StartupTask` toggle, `Unavailable`
9292+when unpackaged), **`CVisualStyle`** (classic-vs-themed font/background), **`Utils`**,
9393+`stdafx.h` (PCH: ATL + shell + common-controls + UxTheme).
60946195## Conventions
62966363-- TCHAR/`_T()` string macros throughout (compiled Unicode), ATL `CString`, and raw Win32 API — match the surrounding style rather than introducing STL strings or wide-only APIs.
6464-- The calculator command protocol is character-based: every user action becomes a single `TCHAR` fed to `calc::change_state`. When adding a key or operation, wire it in both `OnEditKeyDown`/`OnEditChar` (translation) **and** `Calculator.cpp` (behavior), and add a `CALC_*` define in `Calculator.h`.
9797+- TCHAR/`_T()` string macros (Unicode build), ATL `CString`, raw Win32 — match the
9898+ surrounding style.
9999+- The calculator command protocol is character-based: every user action becomes a single
100100+ `TCHAR` fed to `calc::change_state`. To add a key/operation, wire it in
101101+ `OnEditKeyDown`/`OnEditChar` (translation) **and** `Calculator.cpp` (behavior), add a
102102+ `CALC_*` define in `Calculator.h`, and add an engine test in `tests/CalcTests.cpp`.
103103+- Non-ATL source files (`App.cpp`, `TrayIcon.cpp`, `Settings.cpp`, …) do not `using
104104+ namespace ATL`; use `GetModuleHandle(NULL)` for the instance handle rather than
105105+ `_AtlBaseModule`.
106106+- `Calculator.cpp` is set to **NotUsing** the precompiled header (so it compiles standalone
107107+ for the tests); every other `.cpp` uses `stdafx.h`.
+44
docs/superpowers/VERIFICATION.md
···11+# Manual Verification — Windows 11 Tray Calculator
22+33+## Already verified programmatically (this migration)
44+55+- ✅ Engine unit tests: **16/16 pass** (`tests\build-and-run.cmd`) — arithmetic, sqrt,
66+ reciprocal, percent, negate, 000, reset, divide-by-zero, overflow, and Lire/Euro + hex
77+ keys inert.
88+- ✅ Debug **and** Release x64 builds succeed (`msbuild ... /p:Platform=x64`).
99+- ✅ App launches without crashing and stays in its message loop (tray icon added,
1010+ window + EDIT + theme created, anchoring path runs).
1111+- ✅ `Settings` registry round-trip (`PosX`/`PosY` written and read back).
1212+- ✅ `Startup::Get()` returns `Unavailable` when unpackaged (expected).
1313+- ✅ MSIX package builds and is signed (`Packaging\TaskbarCalculator.msix`).
1414+1515+## To verify interactively (requires a desktop session — do these on the machine)
1616+1717+- [ ] Tray icon appears on launch
1818+- [ ] Left-click toggles the window show/hide
1919+- [ ] Window is always-on-top: stays visible above another focused app
2020+- [ ] Keyboard input works: `2 + 3 =` → `5`; divide-by-zero shows the error string;
2121+ sqrt (`q`), percent (`%`), reciprocal (`i`), negate (`p`), `000` (`z`)
2222+- [ ] Regional decimal/thousands separators respected (change in Control Panel, retype)
2323+- [ ] Drag moves the window; position remembered after exit + relaunch
2424+- [ ] First run anchors bottom-right above the tray
2525+- [ ] "X" hides to tray (does not exit)
2626+- [ ] Tray icon returns after restarting Windows Explorer
2727+- [ ] Second launch does not create a duplicate icon (single instance)
2828+- [ ] Exit removes the tray icon and quits
2929+3030+## To verify after installing the MSIX (packaged only)
3131+3232+Install steps (elevated PowerShell — these make machine-level changes, left to the user):
3333+```powershell
3434+# 1) Trust the self-signed dev cert (once):
3535+Import-PfxCertificate -FilePath 'Packaging\TaskbarCalculator.pfx' `
3636+ -CertStoreLocation Cert:\LocalMachine\TrustedPeople `
3737+ -Password (ConvertTo-SecureString 'TaskbarCalc!' -Force -AsPlainText)
3838+# 2) Install the package:
3939+Add-AppxPackage -Path Packaging\TaskbarCalculator.msix
4040+```
4141+4242+- [ ] App installs and appears in Start; launches to the tray
4343+- [ ] Right-click → *Start at login* is enabled/checkable (not grayed)
4444+- [ ] Toggling it on shows the app under Settings → Apps → Startup