// Take a look at the license at the top of the repository in the LICENSE file. use winapi::shared::minwindef::FILETIME; use winapi::shared::minwindef::{DWORD, HKEY}; use winapi::shared::winerror; use winapi::um::winnt::{KEY_READ, LPWSTR}; use winapi::um::winreg::{RegCloseKey, RegOpenKeyExW, RegQueryValueExW}; use std::ffi::OsStr; use std::os::windows::ffi::OsStrExt; use std::time::SystemTime; #[inline] pub(crate) fn filetime_to_u64(f: FILETIME) -> u64 { (f.dwHighDateTime as u64) << 32 | (f.dwLowDateTime as u64) } #[inline] pub(crate) fn get_now() -> u64 { SystemTime::now() .duration_since(SystemTime::UNIX_EPOCH) .map(|n| n.as_secs()) .unwrap_or(0) } pub(crate) unsafe fn to_str(p: LPWSTR) -> String { let mut i = 0; loop { let c = *p.offset(i); if c == 0 { break; } i += 1; } let s = std::slice::from_raw_parts(p, i as _); String::from_utf16(s).unwrap_or_else(|_e| { sysinfo_debug!("Failed to convert to UTF-16 string: {}", _e); String::new() }) } fn utf16_str + ?Sized>(text: &S) -> Vec { OsStr::new(text) .encode_wide() .chain(Some(0).into_iter()) .collect::>() } struct RegKey(HKEY); impl RegKey { unsafe fn open(hkey: HKEY, path: &[u16]) -> Option { let mut new_hkey: HKEY = std::ptr::null_mut(); if RegOpenKeyExW(hkey, path.as_ptr(), 0, KEY_READ, &mut new_hkey) != 0 { return None; } Some(Self(new_hkey)) } unsafe fn get_value(&self, field_name: &[u16], buf: &mut [u8], buf_len: &mut DWORD) -> DWORD { let mut buf_type: DWORD = 0; RegQueryValueExW( self.0, field_name.as_ptr(), std::ptr::null_mut(), &mut buf_type, buf.as_mut_ptr() as _, buf_len, ) as DWORD } } impl Drop for RegKey { fn drop(&mut self) { unsafe { RegCloseKey(self.0); } } } pub(crate) fn get_reg_string_value(hkey: HKEY, path: &str, field_name: &str) -> Option { let c_path = utf16_str(path); let c_field_name = utf16_str(field_name); unsafe { let new_key = RegKey::open(hkey, &c_path)?; let mut buf_len: DWORD = 2048; let mut buf: Vec = Vec::with_capacity(buf_len as usize); loop { match new_key.get_value(&c_field_name, &mut buf, &mut buf_len) { winerror::ERROR_SUCCESS => break, winerror::ERROR_MORE_DATA => { buf.reserve(buf_len as _); } _ => return None, } } buf.set_len(buf_len as _); let words = std::slice::from_raw_parts(buf.as_ptr() as *const u16, buf.len() / 2); let mut s = String::from_utf16_lossy(words); while s.ends_with('\u{0}') { s.pop(); } Some(s) } } pub(crate) fn get_reg_value_u32(hkey: HKEY, path: &str, field_name: &str) -> Option<[u8; 4]> { let c_path = utf16_str(path); let c_field_name = utf16_str(field_name); unsafe { let new_key = RegKey::open(hkey, &c_path)?; let mut buf_len: DWORD = 4; let mut buf = [0u8; 4]; match new_key.get_value(&c_field_name, &mut buf, &mut buf_len) { winerror::ERROR_SUCCESS => Some(buf), _ => None, } } }