如何在 Win32 应用程序中检测 Windows 10 light/dark 模式?

How to detect Windows 10 light/dark mode in Win32 application?

一些上下文:Sciter(纯 win32 应用程序)已经能够呈现 UWP 类似的 UI:

深色模式:

在轻模式下:

Windows 10.1803 在设置小程序中引入 Dark/Light 开关 as seen here for example.

问题:如何确定 Win32 应用程序中 "app mode" 的当前类型?

好吧,这个选项似乎没有直接暴露给常规 Win32 应用程序,但是可以通过 HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize 注册表路径中的 AppsUseLightTheme 键设置/检索它。

编辑:指出这适用于所有 Win32 项目,只要您在启用 c++17 的情况下进行构建。

如果您使用的是最新的 SDK,这对我有用。

#include <winrt/Windows.UI.ViewManagement.h>

using namespace winrt::Windows::UI::ViewManagement;

if (RUNNING_ON_WINDOWS_10) {
  UISettings settings;
  auto background = settings.GetColorValue(UIColorType::Background);
  auto foreground = settings.GetColorValue(UIColorType::Foreground);
}

Microsoft.Windows.SDK.Contracts NuGet package gives .NET Framework 4.5+ and .NET Core 3.0+ applications access to Windows 10 WinRT APIs, including Windows.UI.ViewManagement.Settings mentioned in 。将此包添加到包含以下代码的 .NET Core 3.0 控制台应用程序:

using System;
using Windows.UI.ViewManagement;

namespace WhatColourAmI
{
    class Program
    {
        static void Main(string[] args)
        {

            var settings = new UISettings();
            var foreground = settings.GetColorValue(UIColorType.Foreground);
            var background = settings.GetColorValue(UIColorType.Background);

            Console.WriteLine($"Foreground {foreground} Background {background}");
        }
    }
}

主题设置为深色时的输出为:

Foreground #FFFFFFFF Background #FF000000

当主题设置为 Light 时:

Foreground #FF000000 Background #FFFFFFFF

因为这是通过 Microsoft 提供的包公开的,其中声明:

This package includes all the supported Windows Runtime APIs up to Windows 10 version 1903

可以肯定地说,API 是有意为之的!

注意: 这并没有明确检查主题是 Light 还是 Dark但是检查一对 建议 使用的主题是两者之一的值,所以,.. 这种方法的正确性有点值得怀疑,但它至少是 "pure" C# 实现其他地方用 C++ 概述的方法

添加@user7860670 建议的解决方案,即:检查注册表项 AppsUseLightTheme,我认为值得提供一些代码示例。

要从注册表读取 Win32 有 RegGetValue

C++

bool is_light_theme() {
    // based on 

    // The value is expected to be a REG_DWORD, which is a signed 32-bit little-endian
    auto buffer = std::vector<char>(4);
    auto cbData = static_cast<DWORD>(buffer.size() * sizeof(char));
    auto res = RegGetValueW(
        HKEY_CURRENT_USER,
        L"Software\Microsoft\Windows\CurrentVersion\Themes\Personalize",
        L"AppsUseLightTheme",
        RRF_RT_REG_DWORD, // expected value type
        nullptr,
        buffer.data(),
        &cbData);

    if (res != ERROR_SUCCESS) {
        throw std::runtime_error("Error: error_code=" + std::to_string(res));
    }

    // convert bytes written to our buffer to an int, assuming little-endian
    auto i = int(buffer[3] << 24 |
        buffer[2] << 16 |
        buffer[1] << 8 |
        buffer[0]);

    return i == 1;
}

生锈

使用 windows-rs 投影箱:

pub fn is_light_theme() -> bool {
    // based on 
    let mut buffer: [u8; 4] = [0; 4];
    let mut cb_data: u32 = (buffer.len()).try_into().unwrap();
    let res = unsafe {
        RegGetValueW(
            HKEY_CURRENT_USER,
            r#"Software\Microsoft\Windows\CurrentVersion\Themes\Personalize"#
                .to_wide()
                .as_pwstr(),
            "AppsUseLightTheme".to_wide().as_pwstr(),
            RRF_RT_REG_DWORD,
            std::ptr::null_mut(),
            buffer.as_mut_ptr() as _,
            &mut cb_data as *mut _,
        )
    };
    assert_eq!(
        res,
        ERROR_SUCCESS,
        format!("failed to read key from registry: err_code={}", res).as_str(),
    );

    // REG_DWORD is signed 32-bit, using little endian
    let light_mode = i32::from_le_bytes(buffer) == 1;
    light_mode
}

pub fn is_dark_theme() -> bool {
    !is_light_theme()
}

// convert &str to Win32 PWSTR
#[derive(Default)]
pub struct WideString(pub Vec<u16>);

pub trait ToWide {
    fn to_wide(&self) -> WideString;
}

impl ToWide for &str {
    fn to_wide(&self) -> WideString {
        let mut result: Vec<u16> = self.encode_utf16().collect();
        result.push(0);
        WideString(result)
    }
}

impl ToWide for String {
    fn to_wide(&self) -> WideString {
        let mut result: Vec<u16> = self.encode_utf16().collect();
        result.push(0);
        WideString(result)
    }
}

impl WideString {
    pub fn as_pwstr(&self) -> PWSTR {
        PWSTR(self.0.as_ptr() as *mut _)
    }
}

这是 @user7860670

的答案的 C# 解决方案
using Microsoft.Win32;

try
{
    int res = (int)Registry.GetValue("HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Themes\Personalize", "AppsUseLightTheme", -1);
}
catch 
{
 //Exception Handling     
}
    

res 包含 windows

上默认主题的值

0:深色主题

1 : 浅色主题

-1 : 找不到 AppsUseLightTheme