Dark-Mode für Win32 im Menü

Nachdem mich die Sache mit dem halbherzigen Dark-Mode für Win32 Apps nicht mehr gut schlafen lässt, habe ich gezielt nach Möglichkeiten gesucht, weitere UI Elemente schwarz zu färben.

Einer der störrischen Kandidaten ist die Windows Menüzeile, die durch einige nicht-offizielle APIs beeinflusst werden kann.


UI Control lassen sich oft durch bestimmte Fensternachrichten dazu bringen, “ihre Selbstdarstellung” abzuändern. “Owner-Drawn” ist eines der Schlüsselworte hierfür, und so kann man sich im Notfall fast alle Controls so “hinpatchen”, dass sie zum dunklen Design passen.

Die Windows Menüzeile ist aber so ein ganz spezieller Sonderfall, der nicht von den regulären dokumentierten Nachrichten beeinflusst werden kann.

Eine geniale Zusammenfassung dazu hat github.com/adzm/win32-custom-menubar-aero-theme veröffentlicht, und eben diese Methode setze ich nun auch ein. Und da der Beispielcode so etwas von selbsterklärend ist, brauche ich das hier nicht nochmal durchkauen.

In UAHMenuBar.h findet man die speziellen Fensternachrichten und die struct Deklarationen, in denen zusätzlich Daten gespeichert sind.

Und in UAHMenuBar.cpp wird demonstriert, wie man in der Nachricht WM_UAHDRAWMENUITEM einen Menü-Eintrag selbst kolorieren kann.

Mein Anpassung besteht nun nur noch aus der Abfrage, ob der Dark-Mode aktiviert ist. Wenn dem so ist, sollen die Fensternachrichten alles selbst zeichnen und dafür Dark-Mode-konforme Farben nutzen. Ohne Dark-Mode wird einfach die DefWindowProc aufgerufen

Eine wichtige Frage ist noch:

Wo bekommt man die korrekten Farbinformationen her?

Nun, meine Versuche mit UxGetImmersiveColorTypeFromName() brachten keine guten Ergebnisse.
Mir fehlt ein Mapping von “Menü-Hintergrundfarbe” auf einen ImmersiveXYZ Theme-Color-Namen und alles, was sich “vernünftig” anhörte hat leider nicht gepasst.

Von daher ist meine vorläufige Strategie, die aktuellen Dark-Mode Farben aus einem Explorer-Screen-Shot zu extrahieren und die RGB-Werte hard-coded aufzunehmen.

Das gefällt mir zwar nicht wirklich, aber es ist zumindest eine vorläufige Lösung.

Fazit

Ich bleibe dabei:

Microsoft hätte einfach bei der Anwendung des Explorer oder DarkMode_Explorer Theme-Namens per UxSetWindowTheme() die Controls dunkel zeichnen sollen.

Dann wären uns solche Hacks erspart geblieben.

However… bis ich mit der Dark-Mode Sache zufrieden bin, werden wohl noch einige Code-Änderungen durchs Land ziehen.

Obwohl ich den Menü-Code im Zuge des GATE Frameworks nun ausprobiert habe, werde ich diese Stellen nur optional in ein Kompilat fließen lassen.
Denn da diese Nachrichten nicht dokumentiert sind und mit Zeigern auf private Strukturen gearbeitet wird, ist nicht auszuschließen, dass der Code dann beim nächsten Windows Release zu Crashes führt.

Eine mögliche Lösung wäre natürlich, den Code per Registry-Key aktiveren und deaktivieren zu können.

Na, mal sehen, für was ich mich am Ende entscheiden werde ….