1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
|
use std::{
ffi::OsString,
io, iter,
mem::{self, MaybeUninit},
os::windows::ffi::OsStrExt,
ptr,
};
use winapi::um::{
libloaderapi::{GetModuleHandleW, GetProcAddress},
winnt::RTL_OSVERSIONINFOW,
};
pub fn version() -> String {
let (major, build) = WindowsVersion::new()
.map(|version_info| {
(
version_info.windows_version_string(),
version_info.build_number().to_string(),
)
})
.unwrap_or_else(|_| ("N/A".to_string(), "N/A".to_string()));
format!("Windows {} Build {}", major, build)
}
pub fn short_version() -> String {
let version_string = WindowsVersion::new()
.map(|version| version.windows_version_string())
.unwrap_or("N/A".into());
format!("Windows {}", version_string)
}
pub fn extra_metadata() -> impl Iterator<Item = (String, String)> {
std::iter::empty()
}
pub struct WindowsVersion {
inner: RTL_OSVERSIONINFOW,
}
impl WindowsVersion {
pub fn new() -> Result<WindowsVersion, io::Error> {
let module_name: Vec<u16> = OsString::from("ntdll")
.as_os_str()
.encode_wide()
.chain(iter::once(0u16))
.collect();
let ntdll = unsafe { GetModuleHandleW(module_name.as_ptr()) };
if ntdll == ptr::null_mut() {
return Err(io::Error::last_os_error());
}
let function_address =
unsafe { GetProcAddress(ntdll, b"RtlGetVersion\0" as *const _ as *const i8) };
if function_address == ptr::null_mut() {
return Err(io::Error::last_os_error());
}
let rtl_get_version: extern "stdcall" fn(*mut RTL_OSVERSIONINFOW) =
unsafe { *(&function_address as *const _ as *const _) };
let mut version_info: MaybeUninit<RTL_OSVERSIONINFOW> = mem::MaybeUninit::zeroed();
unsafe {
(*version_info.as_mut_ptr()).dwOSVersionInfoSize =
mem::size_of_val(&version_info) as u32;
rtl_get_version(version_info.as_mut_ptr());
Ok(WindowsVersion {
inner: version_info.assume_init(),
})
}
}
pub fn windows_version_string(&self) -> String {
// Check https://en.wikipedia.org/wiki/List_of_Microsoft_Windows_versions#Personal_computer_versions 'Release version' column
// for the correct NT versions for specific windows releases.
match (self.major_version(), self.minor_version()) {
(6, 1) => "7".into(),
(6, 2) => "8".into(),
(6, 3) => "8.1".into(),
(10, 0) => {
if self.build_number() < 22000 {
"10".into()
} else {
"11".into()
}
}
(major, minor) => format!("{}.{}", major, minor),
}
}
pub fn major_version(&self) -> u32 {
self.inner.dwMajorVersion
}
pub fn minor_version(&self) -> u32 {
self.inner.dwMinorVersion
}
pub fn build_number(&self) -> u32 {
self.inner.dwBuildNumber
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_windows_version() {
WindowsVersion::new().unwrap();
}
}
|