Win10黑暗主题-如何在WINAPI中使用?

时间:2018-11-27 13:53:40

标签: windows winapi themes

October 2018 Update (version 1809)开始,Win10在Windows资源管理器中支持Dark主题。

它可以在这里配置:

  • 用户界面:Desktop | Context Menu | Personalize | Colors | Choose your default app mode = Dark
  • 注册表:HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize\AppsUseLightTheme = DWORD:0

虽然此设置存在一段时间,但仅影响UWP应用程序。但是,在此Windows 10版本中,它也会影响Windows资源管理器,后者是一个桌面应用程序。这意味着Windows现在对其具有内部支持。尽管如此,Windows Explorer以外的桌面应用程序目前不受影响。

我想在我的应用程序中使用它。它是如何实现的?有什么方法(清单,WINAPI等)订阅新的深色主题?

更新1:
我注意到Windows资源管理器的控制面板部分亮而部分暗,因此它应该是每个窗口设置,而不是每个进程设置。

另一个例子:所有桌面应用程序中的“打开文件”对话框均变暗,而应用程序本身仍保持旧的主题。

更新2:
我为SetWindowTheme(hwnd, L"Explorer", NULL);TreeView尝试了ListView。这会明显改变TreeView的样式(+展开按钮变为V),但窗口仍为白色。

3 个答案:

答案 0 :(得分:4)

经过一番挖掘,我找到了这两种方法。两者均未记录,如有更改,恕不另行通知。

1

x = 3

2

SetWindowTheme(hwnd, L"DarkMode_Explorer", NULL);

警告:在其他版本的Windows(包括较新/较旧的Win10版本)上,Ordinal 133可能具有完全不同的API。

这两种方法都可以产生某些效果,但并不是全部。
例如,using TYPE_AllowDarkModeForWindow = bool (WINAPI *)(HWND a_HWND, bool a_Allow); static const TYPE_AllowDarkModeForWindow AllowDarkModeForWindow = (TYPE_AllowDarkModeForWindow)GetProcAddress(hUxtheme, MAKEINTRESOURCEA(133)); AllowDarkModeForWindow(a_HWND, true); SetWindowTheme(hwnd, L"Explorer", NULL); 会为所选项目提供深色滚动条和深色背景,但其余背景保持默认状态。

不幸的是,到目前为止,这还不像“调用函数而已”。看起来,即使应用了正确的主题,某些背景色也需要手动处理。

答案 1 :(得分:2)

请参见https://github.com/ysc3839/win32-darkmode

这家伙用一些不错的可重用代码(MIT许可证)进行了布局。

黑暗模式似乎仍然是Windows 10的一个发展领域,但我相信微软最终将正确记录并将其公开给桌面应用程序。

>

在此之前,我们一直停留在未记录的仅按序输入,然后自定义绘制和WM_CTLCOLOR*消息来指示如何绘制尚不支持本机暗模式的控件。

最基本的新Windows API是 SetPreferredAppMode uxtheme@135)(在创建任何窗口之前都要调用)和 AllowDarkModeForWindow uxtheme@133),以便在任何打算使用本机Windows 10暗模式支持的Window上调用。

以下是该项目的仅按序导入的完整列表:

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

InitDarkMode 以安全的方式导入并初始化暗模式,仔细检查支持的最小和最大Windows 10版本:

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 <= 18363) // Windows 10 1809 10.0.17763 - 1909 10.0.18363
        {
            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();
                }
            }
        }
    }
}

在其他地方,他利用WM_CTLCOLOR*消息和自定义绘制通知的优势在Windows尚未为我们做的地方涂上黑色。

请注意 FixDarkScrollBar 。这是OpenNcThemeData上的IAT钩子,用于覆盖comctl32中的listview类对滚动条主题的选择。那是最困扰我的部分,我正在寻求将其砍掉。我确定他也是。

我已将此代码改编到自己的应用程序中,并且效果很好。但是,我对使用这些未记录的只有序数的API感到不舒服(甚至尽可能安全),并且完全希望Microsoft最终宣布并记录Win32应用程序的暗模式,并使这项工作变得多余。

答案 2 :(得分:-2)

我不确定您是要将主题应用于应用程序,还是只是在应用程序中启用深色主题。

对于第一个,您可以使用SetWindowTheme(hwndList, L"Explorer", NULL);,它可以显示Windows资源管理器列表的外观。

第二个,这是注册表中的键值:HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize\AppsUseLightTheme用于控制主题。 值= 1,表示光线;值= 0,表示暗; 使用注册表API设置值:

#include<iostream>
#include <windows.h>
int main()
{
    HKEY hKey;
    long setRes;
    DWORD dwValue = 1;
    setRes = RegOpenKeyExA(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize", 0, KEY_SET_VALUE, &hKey);
    if (setRes != ERROR_SUCCESS)
    {
        printf("Failed, error %d\n", setRes);
        return -1;
    }
    setRes = RegSetValueExA(hKey, "AppsUseLightTheme", NULL, REG_DWORD, (LPBYTE)&dwValue, sizeof(DWORD));
    if (setRes != ERROR_SUCCESS)
    {
        printf("Failed, error %d\n", setRes);
        return -1;
    }
    RegCloseKey(hKey);
    return 0;
}