Skip to content

Instantly share code, notes, and snippets.

@ericoporto
Forked from rounk-ctrl/Dark.md
Created October 8, 2022 16:12
Show Gist options
  • Select an option

  • Save ericoporto/1745f4b912e22f9eabfce2c7166d979b to your computer and use it in GitHub Desktop.

Select an option

Save ericoporto/1745f4b912e22f9eabfce2c7166d979b to your computer and use it in GitHub Desktop.
Win32 Dark Mode

Dark Mode APIs.

API Signatures.

ShouldAppsUseDarkMode()

Checks whether system is using dark mode or not.
Signature:

using fnShouldAppsUseDarkMode = bool (WINAPI*)(); // ordinal 132

AllowDarkModeForWindow(In HWND hWnd, In bool allow)

Switches the control's theme to the dark variant if available.
Signature:

using fnAllowDarkModeForWindow = bool (WINAPI*)(HWND hWnd, bool allow); // ordinal 133

SetPreferredAppMode(In PreferredAppMode appMode)

Dark Context menu for the app. I don't know what else this does.
Signature(1903+):

using fnSetPreferredAppMode = PreferredAppMode(WINAPI*)(PreferredAppMode appMode); // ordinal 135, in 1903

PreferredAppMode enum

enum class PreferredAppMode
{
   Default,
   AllowDark,
   ForceDark,
   ForceLight,
   Max
};

Actually using them.

First we need to load uxtheme dll as a HMODULE.

HMODULE hUxtheme = LoadLibraryExW(L"uxtheme.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32);

Then we need to get the Process Address of the functions. We already know their ordinal numbers.
First initialize a instance of the signature.

fnSetPreferredAppMode SetPreferredAppMode;

then set the process address by using GetProcAddress

SetPreferredAppMode = (fnSetPreferredAppMode)GetProcAddress(hUxtheme, MAKEINTRESOURCEA(135));

You can do like this for any API. Dont forget to free it

FreeLibrary(hUxtheme);

Usage.

Enables dark context menus which change automatically depending on the theme.

SetPreferredAppMode(PreferredAppMode::AllowDark);

Dark Controls:

First we need to know which all controls support Dark Mode.
If you open aero.msstyles in msstylesEditor, you would be able to see a lot of DarkMode elements.

image
And no you cant just do SetWindowTheme([handle to the control], L"DarkMode_Explorer", NULL);

Button:
SetWindowTheme([handle to the control], L"Explorer", NULL);
AllowDarkModeForWindow([handle to the control], true);
SendMessageW([handle to the control], WM_THEMECHANGED, 0, 0);
Edit:
SetWindowTheme([handle to the control], L"CFD", NULL);
AllowDarkModeForWindow([handle to the control], true);
SendMessageW([handle to the control], WM_THEMECHANGED, 0, 0);
ComboBox:
SetWindowTheme([handle to the control], L"CFD", NULL);
AllowDarkModeForWindow([handle to the control], true);
SendMessageW([handle to the control], WM_THEMECHANGED, 0, 0);
TreeView (maybe):
SetWindowTheme([handle to the control], L"Explorer", NULL);
AllowDarkModeForWindow([handle to the control], true);
SendMessageW([handle to the control], WM_THEMECHANGED, 0, 0);
Dark Scrollbars:

For dark scrollbars you need to iat hook and change the scrollbar theme before its created.
First download this header file and add it to your project. IatHook.h
Then use this function before the creation of HWND.

void FixDarkScrollBar()
{
	HMODULE hComctl = LoadLibraryExW(L"comctl32.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32);
	if (hComctl)
	{
		auto addr = FindDelayLoadThunkInModule(hComctl, "uxtheme.dll", 49); // OpenNcThemeData
		if (addr)
		{
			DWORD oldProtect;
			if (VirtualProtect(addr, sizeof(IMAGE_THUNK_DATA), PAGE_READWRITE, &oldProtect))
			{
				auto MyOpenThemeData = [](HWND hWnd, LPCWSTR classList) -> HTHEME {
					if (wcscmp(classList, L"ScrollBar") == 0)
					{
						hWnd = nullptr;
						classList = L"Explorer::ScrollBar";
					}
					return _OpenNcThemeData(hWnd, classList);
				};

				addr->u1.Function = reinterpret_cast<ULONG_PTR>(static_cast<fnOpenNcThemeData>(MyOpenThemeData));
				VirtualProtect(addr, sizeof(IMAGE_THUNK_DATA), oldProtect, &oldProtect);
			}
		}
	}
}
@ajtruckle

ajtruckle commented Mar 14, 2026 •

Copy link
Copy Markdown

I don't know. But I found a hook for doing the scroll bars:

image

And, radios etc was done using custom draw,

For tab controls, I ended up using TabCtrl which has fabulous dark mode support:

image

And:

image

The latter is using child dialog for the tab content.

@memoarfaa

Copy link
Copy Markdown

Can you please confirm if these controls have bespoke values to pass to SetWindowTheme?

  • Progress Bar
  • Slider

They seem OK to be without any theming from what I can tell:

image

Progress Bar SetWindowTheme will only work in Windows 11 25H2 you can use
https://github.com/memoarfaa/aero-darkmode-parser
for list DarkMode elements
about tab

SetWindowTheme([handle to the control], L"DarkMode_DrakTheme", NULL);  //  Windows 11 25H2
SetWindowTheme([handle to the control], NULL,L"DarkMode::FileExplorerBannerContainer");  // older ver of Windows 11 25H2

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment