HeaderPane
Main

Dark Mode Support

Share Link
Print

SftDarkMode - Windows Dark Mode Helper

SftDarkMode is a single-header helper that adds Windows dark mode support to Win32 dialogs and applications. The header is shared across all Softel vdm DLL controls (SftTree, SftTabs, SftBox, SftMask, SftButton) - the same companion API and color palette is used by every product.

The header provides:

  • A central Init call that detects the user's "Choose your mode" preference, hooks the comctl32 / uxtheme delay-load IAT to dark-theme NC scrollbars, and prepares the shared dark brush.
  • A small set of "apply" functions (ApplyToWindow, ApplyToControl, ApplyToChildren, ApplyToComboBox, ApplyToDialog) that flip the dark title bar, theme class and NC scrollbar opt-in for any Win32 window.
  • A drop-in dialog / window message handler (HandleDialogMessage) that paints WM_CTLCOLOR* surfaces with dark colors, repaints radio-button labels in dark text, and reacts to the live "Choose your mode" toggle through WM_SETTINGCHANGE.
  • An experimental menu-bar drawing handler (HandleMenuMessage) that renders the menu bar and items in dark colors using undocumented Windows messages.
  • Five RGB color constants (SFTDARKMODE_*_COLOR) that define the dark palette - applications can read them when painting their own surfaces against a dark dialog.
  • A GetNaturalChildSize utility for PerMonitorV2 hosts that need to recompute scroll ranges from dialog-template children after a DPI change.

Header layout

SftDarkMode.h is a stb-style single-header library: declarations are always available; the implementation is compiled only when SFTDARKMODE_IMPLEMENTATION is defined before the include. Define it in exactly one .c / .cpp file per executable; include the header without the define everywhere else that needs the declarations.

// In one .c / .cpp file (e.g. DarkMode.cpp):
#define SFTDARKMODE_IMPLEMENTATION
#include "SftDarkMode.h"

// Everywhere else:
#include "SftDarkMode.h"

Application setup

A typical adoption is four call sites:

  1. Process startup (WinMain or CWinApp::InitInstance) - call SftDarkMode_Init once, before any window is created.
  2. Each dialog (WM_INITDIALOG or CDialog::OnInitDialog) - call SftDarkMode_ApplyToDialog on the dialog's HWND. This sets the dark title bar, applies the dark theme class to every direct child, and arms the NC-scrollbar opt-in.
  3. Each dialog or window proc - route messages through SftDarkMode_HandleDialogMessage before the default handler. This paints WM_CTLCOLOR* responses with dark colors and re-applies dark mode automatically when the user flips the Windows setting at runtime.
  4. Optional toggle - to add an in-application Light / Dark toggle, call SftDarkMode_SetActive when the user flips the toggle and re-call SftDarkMode_ApplyToDialog on every visible dialog.

Each Softel vdm control honors the dark state automatically when its own SetDarkMode is set to AUTO (or stays in OFF when the application has not opted in).

Functions

FunctionDescription
SftDarkMode_InitInitialize the dark-mode helper. Call once at application startup, before creating any windows.
SftDarkMode_IsActiveReturns TRUE if dark mode is currently active.
SftDarkMode_SetActiveOverride the dark / light state programmatically.
SftDarkMode_ApplyToWindowApply dark mode to a top-level window's non-client area (title bar, frame).
SftDarkMode_ApplyToControlApply dark mode theming to a single control. Picks the correct theme class for the control's window class.
SftDarkMode_ApplyToChildrenApply dark mode theming to every direct child of a window.
SftDarkMode_ApplyToComboBoxApply dark mode to a combo box (parent and its internal children).
SftDarkMode_ApplyToDialogApply dark mode to a dialog and all its children. The recommended one-shot call from WM_INITDIALOG.
SftDarkMode_GetNaturalChildSizeCompute the natural content size of a form-style window by unioning the bounding rects of its direct children. Useful for CScrollView::SetScrollSizes after a PerMonitorV2 DPI change.
SftDarkMode_HandleDialogMessageHandle dark-mode dialog / window messages (WM_CTLCOLOR*, WM_NOTIFY radio buttons, WM_SETTINGCHANGE). Aliased as SftDarkMode_HandleWindowMessage when called from a window proc.
SftDarkMode_HandleMenuMessageExperimental. Draw the menu bar and items in dark colors using undocumented Windows messages.

Constants

ConstantValuePurpose
SFTDARKMODE_BG_COLORRGB(32, 32, 32)Dark background fill - used for the dialog client area and the dark brush returned from WM_CTLCOLOR*.
SFTDARKMODE_TEXT_COLORRGB(230, 230, 230)Dark-mode text color.
SFTDARKMODE_BTNFACE_COLORRGB(45, 45, 45)Dark button-face / panel color (slightly lighter than the dialog background).
SFTDARKMODE_HOT_COLORRGB(55, 55, 55)Dark "hot" / hover background.
SFTDARKMODE_PRESSED_COLORRGB(32, 32, 32)Dark pressed-state background (matches BG so a pressed button visually merges with the dialog).
SFTDARKMODE_IMPLEMENTATION(preprocessor)Define before #include "SftDarkMode.h" in exactly one source file to compile the implementation.

Platform requirements

Dark mode is a Windows 10 (1809+) and Windows 11 feature. SftDarkMode degrades gracefully on earlier platforms - the helper functions are still callable and return safely, but no dark-mode chrome is applied. Several APIs the helper uses (SetPreferredAppMode, AllowDarkModeForWindow, RefreshImmersiveColorPolicyState, FlushMenuThemes) are undocumented uxtheme.dll exports loaded by ordinal at runtime.

ANSI vs Unicode applications

The header itself is character-set neutral - it uses WCHAR string comparisons internally for the ImmersiveColorSet setting name and accepts both LPCWSTR and LPCSTR forms of the WM_SETTINGCHANGE lParam so it runs correctly under both Unicode and MultiByte (ANSI) procedures.

Linked libraries

The header issues #pragma comment(lib, ...) directives for dwmapi.lib and uxtheme.lib when compiled under Microsoft Visual C++. No additional linker setup is required.


Last Updated 05/09/2026 - (email)
© 2026 Softel vdm, Inc.