winbrew_windows\system/
version.rs

1use winreg::{RegKey, enums::HKEY_LOCAL_MACHINE};
2
3const WINDOWS_CURRENT_VERSION_KEY: &str = r"SOFTWARE\Microsoft\Windows NT\CurrentVersion";
4const CURRENT_MAJOR_VERSION_NUMBER: &str = "CurrentMajorVersionNumber";
5const CURRENT_MINOR_VERSION_NUMBER: &str = "CurrentMinorVersionNumber";
6const CURRENT_VERSION: &str = "CurrentVersion";
7const CURRENT_BUILD_NUMBER: &str = "CurrentBuildNumber";
8const CURRENT_BUILD: &str = "CurrentBuild";
9const UBR: &str = "UBR";
10
11/// Return the current Windows version string when the registry exposes it.
12pub fn windows_version_string() -> Option<String> {
13    let hklm = RegKey::predef(HKEY_LOCAL_MACHINE);
14    let Ok(current_version_key) = hklm.open_subkey(WINDOWS_CURRENT_VERSION_KEY) else {
15        return None;
16    };
17
18    let major = current_version_key
19        .get_value::<u32, _>(CURRENT_MAJOR_VERSION_NUMBER)
20        .ok();
21    let minor = current_version_key
22        .get_value::<u32, _>(CURRENT_MINOR_VERSION_NUMBER)
23        .ok();
24    let prefix = match (major, minor) {
25        (Some(major), Some(minor)) => format!("{major}.{minor}"),
26        _ => current_version_key
27            .get_value::<String, _>(CURRENT_VERSION)
28            .ok()?
29            .trim()
30            .to_string(),
31    };
32
33    let build = current_version_key
34        .get_value::<String, _>(CURRENT_BUILD_NUMBER)
35        .ok()
36        .or_else(|| {
37            current_version_key
38                .get_value::<String, _>(CURRENT_BUILD)
39                .ok()
40        })?;
41
42    let ubr = current_version_key.get_value::<u32, _>(UBR).ok();
43
44    format_windows_version(&prefix, &build, ubr)
45}
46
47fn format_windows_version(prefix: &str, build: &str, ubr: Option<u32>) -> Option<String> {
48    let prefix = prefix.trim();
49    let build = build.trim();
50
51    if prefix.is_empty() || build.is_empty() {
52        return None;
53    }
54
55    let mut version = format!("{prefix}.{build}");
56    if let Some(ubr) = ubr {
57        version.push('.');
58        version.push_str(&ubr.to_string());
59    }
60
61    Some(version)
62}
63
64#[cfg(test)]
65mod tests {
66    use super::format_windows_version;
67
68    #[test]
69    fn formats_windows_version_strings() {
70        assert_eq!(
71            format_windows_version("10.0", "26200", Some(8246)),
72            Some("10.0.26200.8246".to_string())
73        );
74        assert_eq!(
75            format_windows_version("6.3", "9600", None),
76            Some("6.3.9600".to_string())
77        );
78        assert_eq!(format_windows_version("", "9600", Some(1)), None);
79        assert_eq!(format_windows_version("10.0", "", Some(1)), None);
80    }
81}