blob: 96132117e72b51226050d8b84208168a903fd9f1 [file] [log] [blame]
// 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<S: AsRef<OsStr> + ?Sized>(text: &S) -> Vec<u16> {
OsStr::new(text)
.encode_wide()
.chain(Some(0).into_iter())
.collect::<Vec<_>>()
}
struct RegKey(HKEY);
impl RegKey {
unsafe fn open(hkey: HKEY, path: &[u16]) -> Option<Self> {
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<String> {
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<u8> = 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,
}
}
}