1pub mod monitor;
2
3use std::fmt::Write as FmtWrite;
4use std::io::Write as IoWrite;
5use std::{
6 fs::File,
7 io::{self},
8 mem::ManuallyDrop,
9 path::Path,
10};
11use winreg::{
12 enums::{RegType, KEY_QUERY_VALUE, KEY_SET_VALUE},
13 RegKey, RegValue, HKEY,
14};
15
16pub struct RegValuePath<'a> {
17 pub hkey: HKEY,
18 pub subkey_path: &'a str,
19 pub value_name: &'a str,
20}
21
22pub fn read_reg_bin_value(reg_value_path: &RegValuePath) -> Result<Vec<u8>, io::Error> {
23 let key = RegKey::predef(reg_value_path.hkey)
24 .open_subkey_with_flags(reg_value_path.subkey_path, KEY_QUERY_VALUE)?;
25 let value = key.get_raw_value(reg_value_path.value_name)?;
26
27 if value.vtype == RegType::REG_BINARY {
28 Ok(value.bytes)
29 } else {
30 Err(io::Error::new(
31 io::ErrorKind::InvalidData,
32 "expected binary value",
33 ))
34 }
35}
36
37pub fn write_reg_bin_value(
38 reg_value_path: &RegValuePath,
39 bytes: &Vec<u8>,
40) -> Result<(), io::Error> {
41 let key = RegKey::predef(reg_value_path.hkey)
42 .open_subkey_with_flags(reg_value_path.subkey_path, KEY_SET_VALUE)?;
43
44 let unsafe_reg_value = ManuallyDrop::new(RegValue {
46 vtype: RegType::REG_BINARY,
47 bytes: unsafe { Vec::from_raw_parts(bytes.as_ptr() as _, bytes.len(), bytes.capacity()) },
49 });
50
51 let result = key.set_raw_value(reg_value_path.value_name, &unsafe_reg_value);
53
54 let RegValue { bytes, .. } = ManuallyDrop::into_inner(unsafe_reg_value);
56 let _ = ManuallyDrop::new(bytes);
57
58 result?;
59 Ok(())
60}
61
62pub(crate) fn export_reg_bin_values<T: AsRef<Path>>(
63 reg_value_paths: &[RegValuePath],
64 file_path: T,
65) -> Result<(), io::Error> {
66 let io_error = |_| io::Error::from(io::ErrorKind::Other);
70
71 let mut text = String::with_capacity(2048);
72
73 text.push_str("\u{feff}Windows Registry Editor Version 5.00\r\n");
74 text.push_str("\r\n");
75
76 for reg_value_path in reg_value_paths {
77 write!(
78 text,
79 "[{}\\{}]\r\n",
80 hkey_to_str(reg_value_path.hkey),
81 reg_value_path.subkey_path
82 )
83 .map_err(io_error)?;
84
85 write!(text, "\"{}\"=hex:", reg_value_path.value_name).map_err(io_error)?;
86
87 let mut first = true;
88 for byte in read_reg_bin_value(reg_value_path)? {
89 write!(text, "{}{:02x}", if first { "" } else { "," }, byte).map_err(io_error)?;
90 first = false;
91 }
92
93 text.push_str("\r\n");
94 text.push_str("\r\n");
95 }
96
97 let mut file = File::create(file_path)?;
99 for int16 in text.encode_utf16() {
100 file.write(&int16.to_le_bytes())?;
101 }
102
103 Ok(())
104}
105
106pub(crate) fn delete_reg_value(reg_value_path: &RegValuePath) -> Result<(), io::Error> {
107 let key = RegKey::predef(reg_value_path.hkey)
108 .open_subkey_with_flags(reg_value_path.subkey_path, KEY_SET_VALUE)?;
109
110 key.delete_value(reg_value_path.value_name)
111 .or_else(|error| {
112 if error.kind() == io::ErrorKind::NotFound {
113 Ok(())
114 } else {
115 Err(error)
116 }
117 })
118}
119
120const fn hkey_to_str(hkey: HKEY) -> &'static str {
121 use winreg::enums::*;
122
123 match hkey {
124 HKEY_CLASSES_ROOT => "HKEY_CLASSES_ROOT",
125 HKEY_CURRENT_USER => "HKEY_CURRENT_USER",
126 HKEY_LOCAL_MACHINE => "HKEY_LOCAL_MACHINE",
127 HKEY_USERS => "HKEY_USERS",
128 HKEY_PERFORMANCE_DATA => "HKEY_PERFORMANCE_DATA",
129 HKEY_PERFORMANCE_TEXT => "HKEY_PERFORMANCE_TEXT",
130 HKEY_PERFORMANCE_NLSTEXT => "HKEY_PERFORMANCE_NLSTEXT",
131 HKEY_CURRENT_CONFIG => "HKEY_CURRENT_CONFIG",
132 HKEY_DYN_DATA => "HKEY_DYN_DATA",
133 HKEY_CURRENT_USER_LOCAL_SETTINGS => "HKEY_CURRENT_USER_LOCAL_SETTINGS",
134 _ => panic!("unknown `HKEY`"),
135 }
136}