I'm creating a windows app that can change system color.
I saw this code, where we are accessing and reading from registry with RegGetValueW(). Then I copied and changed it a little with the help of compiler:
use windows::{Win32::System::Registry::RegGetValueW, core::PWSTR};
use winreg::enums::*;
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,
w!(r#"Software\Microsoft\Windows\CurrentVersion\Themes\Personalize"#),
w!("AppsUseLightTheme"),
RRF_RT_REG_DWORD,
Some(std::ptr::null_mut()),
Some(buffer.as_mut_ptr() as _),
Some(&mut cb_data as *mut u32),
)
};
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 _)
}
}
From where is it getting HKEY_CURRENT_USER, RRF_RT_REG_DWORD, ERROR_SUCCESS?
I'm getting HKEY_CURRENT_USER with help of winreg crate, but I assume you can get HKEY_CURRENT_USER, RRF_RT_REG_DWORD from windows-rs directly, couldn't find this info.
I know that this code will not change system colors, reading theme value from registry is the closest target for me right now.
The first question revolves around discoverability. The current situation isn't great and you will have to look up information in two places:
The first resource answers the question of where to find any given symbol. Both
HKEY_CURRENT_USERandRRF_RT_REG_DWORDare exported from thewindows::Win32::System::Registrymodule. (I'd link to the documentation, but those links may no longer be correct when the next version is published1.)ERROR_SUCCESSis exported from thewindows::Win32::Foundationmodule, a foundational module used across the entire API.Once you know which modules to
useyou have to make sure to enable the respective features. That's what the second resource is for. The only feature you need here is"Win32_System_Registry"; thewindows::Win32::Foundationmodule is no longer feature-gated.The second question is concerned with string representations. Rust's internal string representation is unfortunately alien to Windows' and work is required to bridge the impedance mismatch. The
windowscrate provides basic translation primitives. For string literals, you can use thew!macro that re-encodes the source string as UTF-16, appends a NUL character and returns aPCWSTRready for use.The following compiles and runs as expected:
main.rs
Cargo.toml
There's no need to use the
winregcrate.As an alternative, you could use the
windows-registryinstead. It is part of the same repository as thewindowscrate. This vastly cuts down on the amount of code you need to write.main.rs
Cargo.toml
1 Unfortunately,
docs.rsis unable to handle thewindowscrate, and the crate maintainers are forced to entertain a custom hosting solution with a fire-and-forget data retention policy.