use windows::core::HRESULT;
use windows::Win32::Foundation::GetLastError;
use windows::Win32::Foundation::ERROR_OLD_WIN_VERSION;
use windows::Win32::System::SystemInformation::{VerSetConditionMask, VerifyVersionInfoA};
use windows::Win32::System::SystemInformation::{
OSVERSIONINFOEXA, VER_MAJORVERSION, VER_MINORVERSION, VER_SERVICEPACKMAJOR,
};
#[derive(Debug)]
pub enum VersionHelperError {
IoError(std::io::Error),
}
pub(crate) type VersionHelperResult<T> = Result<T, VersionHelperError>;
type OsVersionInfo = OSVERSIONINFOEXA;
const VER_GREATER_OR_EQUAL: u8 = windows::Win32::System::SystemServices::VER_GREATER_EQUAL as u8;
fn verify_system_version(major: u8, minor: u8, sp_major: u16) -> VersionHelperResult<bool> {
let mut os_version = OsVersionInfo {
dwOSVersionInfoSize: std::mem::size_of::<OsVersionInfo>() as u32,
dwMajorVersion: major as u32,
dwMinorVersion: minor as u32,
wServicePackMajor: sp_major,
..Default::default()
};
let mut condition_mask = 0;
let res = unsafe {
condition_mask =
VerSetConditionMask(condition_mask, VER_MAJORVERSION, VER_GREATER_OR_EQUAL);
condition_mask =
VerSetConditionMask(condition_mask, VER_MINORVERSION, VER_GREATER_OR_EQUAL);
condition_mask =
VerSetConditionMask(condition_mask, VER_SERVICEPACKMAJOR, VER_GREATER_OR_EQUAL);
VerifyVersionInfoA(
&mut os_version,
VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR,
condition_mask,
)
};
match res {
Ok(_) => Ok(true),
Err(e) => match e.code() {
e if e == HRESULT::from_win32(ERROR_OLD_WIN_VERSION.0) => Ok(false),
_ => Err(VersionHelperError::IoError(
std::io::Error::from_raw_os_error(unsafe { GetLastError() }.0 as i32),
)),
},
}
}
pub fn is_win8_or_greater() -> bool {
match verify_system_version(6, 2, 0) {
Ok(res) => res,
Err(err) => {
log::warn!("Unable ro verify system version: {:?}", err);
true
}
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_verify_system_version() {
match verify_system_version(5, 1, 0) {
Ok(res) => assert!(res),
Err(err) => panic!("VersionHelper error: {:?}", err),
};
}
}