To add to the solution suggested by @user7860670, i.e: checking the registry key AppsUseLightTheme
, I think it is worth having some code example.
To read from the registry Win32 has RegGetValue.
C++
bool is_light_theme() {
// based on https://stackoverflow.com/questions/51334674/how-to-detect-windows-10-light-dark-mode-in-win32-application
// 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;
}
Rust
Using the windows-rs projection crate:
pub fn is_light_theme() -> bool {
// based on https://stackoverflow.com/a/51336913/709884
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 _)
}
}