diff options
Diffstat (limited to 'DarkMode.h')
-rw-r--r-- | DarkMode.h | 184 |
1 files changed, 184 insertions, 0 deletions
diff --git a/DarkMode.h b/DarkMode.h new file mode 100644 index 0000000..207ff6a --- /dev/null +++ b/DarkMode.h @@ -0,0 +1,184 @@ +// https://github.com/ysc3839/win32-darkmode/blob/master/win32-darkmode/DarkMode.h + +#pragma once +#include <Windows.h> +#include <dwmapi.h> +//#include "IatHook.h" + +enum IMMERSIVE_HC_CACHE_MODE +{ + IHCM_USE_CACHED_VALUE, + IHCM_REFRESH +}; + +// Insider 18334 +enum PreferredAppMode +{ + Default, + AllowDark, + ForceDark, + ForceLight, + Max +}; + +using fnRtlGetNtVersionNumbers = void (WINAPI *)(LPDWORD major, LPDWORD minor, LPDWORD build); +// 1809 17763 +using fnShouldAppsUseDarkMode = bool (WINAPI *)(); // ordinal 132 +using fnAllowDarkModeForWindow = bool (WINAPI *)(HWND hWnd, bool allow); // ordinal 133 +using fnAllowDarkModeForApp = bool (WINAPI *)(bool allow); // ordinal 135, removed since 18334 +using fnFlushMenuThemes = void (WINAPI *)(); // ordinal 136 +using fnRefreshImmersiveColorPolicyState = void (WINAPI *)(); // ordinal 104 +using fnIsDarkModeAllowedForWindow = bool (WINAPI *)(HWND hWnd); // ordinal 137 +using fnGetIsImmersiveColorUsingHighContrast = bool (WINAPI *)(IMMERSIVE_HC_CACHE_MODE mode); // ordinal 106 +using fnOpenNcThemeData = HTHEME(WINAPI *)(HWND hWnd, LPCWSTR pszClassList); // ordinal 49 + // Insider 18290 +using fnShouldSystemUseDarkMode = bool (WINAPI *)(); // ordinal 138 + // Insider 18334 +using fnSetPreferredAppMode = PreferredAppMode(WINAPI *)(PreferredAppMode appMode); // ordinal 135, since 18334 +using fnIsDarkModeAllowedForApp = bool (WINAPI *)(); // ordinal 139 + +fnShouldAppsUseDarkMode _ShouldAppsUseDarkMode = nullptr; +fnAllowDarkModeForWindow _AllowDarkModeForWindow = nullptr; +fnAllowDarkModeForApp _AllowDarkModeForApp = nullptr; +fnFlushMenuThemes _FlushMenuThemes = nullptr; +fnRefreshImmersiveColorPolicyState _RefreshImmersiveColorPolicyState = nullptr; +fnIsDarkModeAllowedForWindow _IsDarkModeAllowedForWindow = nullptr; +fnGetIsImmersiveColorUsingHighContrast _GetIsImmersiveColorUsingHighContrast = nullptr; +fnOpenNcThemeData _OpenNcThemeData = nullptr; +// Insider 18290 +fnShouldSystemUseDarkMode _ShouldSystemUseDarkMode = nullptr; +// Insider 18334 +fnSetPreferredAppMode _SetPreferredAppMode = nullptr; + +bool g_darkModeSupported = false; +bool g_darkModeEnabled = false; +DWORD g_buildNumber = 0; + +bool AllowDarkModeForWindow(HWND hWnd, bool allow) +{ + if (g_darkModeSupported) + return _AllowDarkModeForWindow(hWnd, allow); + return false; +} + +bool IsHighContrast() +{ + HIGHCONTRASTW highContrast = { sizeof(highContrast) }; + if (SystemParametersInfoW(SPI_GETHIGHCONTRAST, sizeof(highContrast), &highContrast, FALSE)) + return highContrast.dwFlags & HCF_HIGHCONTRASTON; + return false; +} + +void RefreshTitleBarThemeColor(HWND hWnd) +{ + BOOL dark = FALSE; + if (_IsDarkModeAllowedForWindow(hWnd) && + _ShouldAppsUseDarkMode() && + !IsHighContrast()) + { + dark = TRUE; + } + DwmSetWindowAttribute(hWnd, 19, &dark, sizeof(dark)); +} + +bool IsColorSchemeChangeMessage(LPARAM lParam) +{ + bool is = false; + if (lParam && CompareStringOrdinal(reinterpret_cast<LPCWCH>(lParam), -1, L"ImmersiveColorSet", -1, TRUE) == CSTR_EQUAL) + { + _RefreshImmersiveColorPolicyState(); + is = true; + } + _GetIsImmersiveColorUsingHighContrast(IHCM_REFRESH); + return is; +} + +bool IsColorSchemeChangeMessage(UINT message, LPARAM lParam) +{ + if (message == WM_SETTINGCHANGE) + return IsColorSchemeChangeMessage(lParam); + return false; +} + +void AllowDarkModeForApp(bool allow) +{ + if (_AllowDarkModeForApp) + _AllowDarkModeForApp(allow); + else if (_SetPreferredAppMode) + _SetPreferredAppMode(allow ? AllowDark : Default); +} + +void FixDarkScrollBar() +{ +#if 0 + auto addr = FindDelayLoadThunkInModule(GetModuleHandleW(L"comctl32.dll"), "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); + } + } +#endif +} + +void InitDarkMode() +{ + fnRtlGetNtVersionNumbers RtlGetNtVersionNumbers = reinterpret_cast<fnRtlGetNtVersionNumbers>(GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "RtlGetNtVersionNumbers")); + if (RtlGetNtVersionNumbers) + { + DWORD major, minor; + RtlGetNtVersionNumbers(&major, &minor, &g_buildNumber); + g_buildNumber &= ~0xF0000000; + if (major == 10 && minor == 0 && 17763 <= g_buildNumber && g_buildNumber <= 18362) // Windows 10 1809 10.0.17763 - 1903 10.0.18362 + { + HMODULE hUxtheme = LoadLibraryExW(L"uxtheme.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32); + if (hUxtheme) + { + _OpenNcThemeData = reinterpret_cast<fnOpenNcThemeData>(GetProcAddress(hUxtheme, MAKEINTRESOURCEA(49))); + _RefreshImmersiveColorPolicyState = reinterpret_cast<fnRefreshImmersiveColorPolicyState>(GetProcAddress(hUxtheme, MAKEINTRESOURCEA(104))); + _GetIsImmersiveColorUsingHighContrast = reinterpret_cast<fnGetIsImmersiveColorUsingHighContrast>(GetProcAddress(hUxtheme, MAKEINTRESOURCEA(106))); + _ShouldAppsUseDarkMode = reinterpret_cast<fnShouldAppsUseDarkMode>(GetProcAddress(hUxtheme, MAKEINTRESOURCEA(132))); + _AllowDarkModeForWindow = reinterpret_cast<fnAllowDarkModeForWindow>(GetProcAddress(hUxtheme, MAKEINTRESOURCEA(133))); + + auto ord135 = GetProcAddress(hUxtheme, MAKEINTRESOURCEA(135)); + if (g_buildNumber < 18334) + _AllowDarkModeForApp = reinterpret_cast<fnAllowDarkModeForApp>(ord135); + else + _SetPreferredAppMode = reinterpret_cast<fnSetPreferredAppMode>(ord135); + + //_FlushMenuThemes = reinterpret_cast<fnFlushMenuThemes>(GetProcAddress(hUxtheme, MAKEINTRESOURCEA(136))); + _IsDarkModeAllowedForWindow = reinterpret_cast<fnIsDarkModeAllowedForWindow>(GetProcAddress(hUxtheme, MAKEINTRESOURCEA(137))); + + if (_OpenNcThemeData && + _RefreshImmersiveColorPolicyState && + _ShouldAppsUseDarkMode && + _AllowDarkModeForWindow && + (_AllowDarkModeForApp || _SetPreferredAppMode) && + //_FlushMenuThemes && + _IsDarkModeAllowedForWindow) + { + g_darkModeSupported = true; + + AllowDarkModeForApp(true); + _RefreshImmersiveColorPolicyState(); + + g_darkModeEnabled = _ShouldAppsUseDarkMode() && !IsHighContrast(); + + FixDarkScrollBar(); + } + } + } + } +} |