Skip to content

Modernize: .NET 10, CsWin32, H.NotifyIcon - #30

Open
spamsch wants to merge 1 commit into
shayne:mainfrom
spamsch:modernize
Open

spamsch wants to merge 1 commit into
shayne:mainfrom
spamsch:modernize

Conversation

@spamsch

@spamsch spamsch commented Sep 20, 2026

Copy link
Copy Markdown

Modernizes the app onto current .NET and current dependencies.

Platform and dependencies

  • net6.0 (end of life) → net10.0
  • ModernNotifyIcon (unmaintained since 2021) → H.NotifyIcon, which drops the Windows Forms dependency entirely and lets the tray menu follow the system light/dark theme
  • Config.Net → System.Text.Json with a source-generated context; settings move to %APPDATA%\PowerDimmer, so a writable install folder is no longer required (an old settings.json beside the exe is still read once)
  • NHotkey.Wpf 2.1.0 → 4.0.0
  • Hand-written P/Invoke → CsWin32 source generation

Results

  • Published single file: 26.7 MB → 1.3 MB, mostly by dropping a WinRT projection assembly the app never used
  • Build warnings: 14 → 0

Fixes found along the way

  • Window shades kept their event callback in a shared static field, so a second shade orphaned the first one's hook
  • Shades fought for z-order via a 500 ms sleep on a background thread; they now sit directly above their target window
  • Turning off "Dim taskbar" never restored the taskbar
  • The area picker broke when dragging up or left, and had no way to cancel
  • Dim overlays ignored monitors being added or rearranged
  • A hotkey already claimed by another app stopped startup

Verified on Windows 11: dimming measurably darkens the screen, settings round-trip including the old file format, and the tray menu bindings work in both directions.

🤖 Generated with Claude Code

Target framework moves from the end-of-life net6.0-windows10.0.19041.0 to
net10.0-windows. Dropping the Windows SDK projection target removes
Microsoft.Windows.SDK.NET.dll (24.9 MB) from the output; nothing in the app
used WinRT. A published single-file build goes from 26.7 MB to 1.3 MB.

Dependencies:
* ModernNotifyIcon (abandoned since 2021) -> H.NotifyIcon.Wpf 2.4.1. The tray
  menu is plain WPF now, so WindowsForms is gone entirely and the menu follows
  the system light/dark setting through the Fluent theme instead of a
  hard-coded palette.
* Config.Net -> System.Text.Json with a source-generated context. Settings move
  to %APPDATA%\PowerDimmer and no longer need a writable install directory; an
  old settings.json beside the executable is still read once.
* NHotkey.Wpf 2.1.0 -> 4.0.0.
* Hand-written P/Invoke (Win32.cs, Win32Util.cs) -> Microsoft.Windows.CsWin32
  source generation driven by NativeMethods.txt.

Fixes found along the way:
* WindowShade parked its WinEvent callback in a static GCHandle, so opening a
  second shade overwrote the first one's handle and left Windows calling a
  collectable delegate. Each hook now owns its callback and unhooks on dispose.
* Shades were flipped topmost and back after a 500 ms Thread.Sleep on a
  background thread. They are now placed directly above their target window in
  the z-order, which is race-free.
* Turning off "Dim taskbar" never restored the taskbar; it stayed buried until
  something else raised it. Exiting no longer rewrites the saved preference.
* The area picker produced a negative-size rectangle when dragging up or left,
  and had no way to cancel. Corners are normalised, Escape and right-click
  cancel, and the selection converts to physical pixels so it lands correctly
  on a scaled display.
* Dim overlays were fixed at startup and ignored monitor changes. They are
  rebuilt on DisplaySettingsChanged, using EnumDisplayMonitors in place of the
  WinForms Screen.AllScreens call.
* A hotkey already owned by another app threw and stopped startup.
* Destroyed windows stayed in the pinned-handle set forever.

The app manifest declares PerMonitorV2 DPI awareness, and all overlay
positioning is done in physical pixels so multi-monitor mixed-DPI setups place
overlays correctly.

Builds clean with zero warnings; the previous tree had 14.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant