// Copyright 2015, Igor Shaula // Licensed under the MIT License . This file // may not be copied, modified, or distributed // except according to those terms. //! Crate for accessing MS Windows registry //! //!## Usage //! //!### Basic usage //! //!```toml,ignore //!# Cargo.toml //![dependencies] //!winreg = "0.10" //!``` //! //!```no_run //!extern crate winreg; //!use std::io; //!use std::path::Path; //!use winreg::enums::*; //!use winreg::RegKey; //! //!fn main() -> io::Result<()> { //! println!("Reading some system info..."); //! let hklm = RegKey::predef(HKEY_LOCAL_MACHINE); //! let cur_ver = hklm.open_subkey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion")?; //! let pf: String = cur_ver.get_value("ProgramFilesDir")?; //! let dp: String = cur_ver.get_value("DevicePath")?; //! println!("ProgramFiles = {}\nDevicePath = {}", pf, dp); //! let info = cur_ver.query_info()?; //! println!("info = {:?}", info); //! let mt = info.get_last_write_time_system(); //! println!( //! "last_write_time as winapi::um::minwinbase::SYSTEMTIME = {}-{:02}-{:02} {:02}:{:02}:{:02}", //! mt.wYear, mt.wMonth, mt.wDay, mt.wHour, mt.wMinute, mt.wSecond //! ); //! //! // enable `chrono` feature on `winreg` to make this work //! // println!( //! // "last_write_time as chrono::NaiveDateTime = {}", //! // info.get_last_write_time_chrono() //! // ); //! //! println!("And now lets write something..."); //! let hkcu = RegKey::predef(HKEY_CURRENT_USER); //! let path = Path::new("Software").join("WinregRsExample1"); //! let (key, disp) = hkcu.create_subkey(&path)?; //! //! match disp { //! REG_CREATED_NEW_KEY => println!("A new key has been created"), //! REG_OPENED_EXISTING_KEY => println!("An existing key has been opened"), //! } //! //! key.set_value("TestSZ", &"written by Rust")?; //! let sz_val: String = key.get_value("TestSZ")?; //! key.delete_value("TestSZ")?; //! println!("TestSZ = {}", sz_val); //! //! key.set_value("TestMultiSZ", &vec!["written", "by", "Rust"])?; //! let multi_sz_val: Vec = key.get_value("TestMultiSZ")?; //! key.delete_value("TestMultiSZ")?; //! println!("TestMultiSZ = {:?}", multi_sz_val); //! //! key.set_value("TestDWORD", &1234567890u32)?; //! let dword_val: u32 = key.get_value("TestDWORD")?; //! println!("TestDWORD = {}", dword_val); //! //! key.set_value("TestQWORD", &1234567891011121314u64)?; //! let qword_val: u64 = key.get_value("TestQWORD")?; //! println!("TestQWORD = {}", qword_val); //! //! key.create_subkey("sub\\key")?; //! hkcu.delete_subkey_all(&path)?; //! //! println!("Trying to open nonexistent key..."); //! hkcu.open_subkey(&path).unwrap_or_else(|e| match e.kind() { //! io::ErrorKind::NotFound => panic!("Key doesn't exist"), //! io::ErrorKind::PermissionDenied => panic!("Access denied"), //! _ => panic!("{:?}", e), //! }); //! Ok(()) //!} //!``` //! //!### Iterators //! //!```no_run //!extern crate winreg; //!use std::io; //!use winreg::RegKey; //!use winreg::enums::*; //! //!fn main() -> io::Result<()> { //! println!("File extensions, registered in system:"); //! for i in RegKey::predef(HKEY_CLASSES_ROOT) //! .enum_keys().map(|x| x.unwrap()) //! .filter(|x| x.starts_with(".")) //! { //! println!("{}", i); //! } //! //! let system = RegKey::predef(HKEY_LOCAL_MACHINE) //! .open_subkey("HARDWARE\\DESCRIPTION\\System")?; //! for (name, value) in system.enum_values().map(|x| x.unwrap()) { //! println!("{} = {:?}", name, value); //! } //! //! Ok(()) //!} //!``` //! #[cfg(feature = "chrono")] extern crate chrono; #[cfg(feature = "serialization-serde")] extern crate serde; extern crate winapi; use enums::*; use std::default::Default; use std::ffi::OsStr; use std::fmt; use std::io; use std::mem::transmute; use std::os::windows::ffi::OsStrExt; use std::ptr; use std::slice; #[cfg(feature = "transactions")] use transaction::Transaction; use types::{FromRegValue, ToRegValue}; pub use winapi::shared::minwindef::HKEY; use winapi::shared::minwindef::{BYTE, DWORD, FILETIME, LPBYTE}; use winapi::shared::winerror; use winapi::um::minwinbase::SYSTEMTIME; use winapi::um::timezoneapi::FileTimeToSystemTime; use winapi::um::winnt::{self, WCHAR}; use winapi::um::winreg as winapi_reg; macro_rules! werr { ($e:expr) => { Err(io::Error::from_raw_os_error($e as i32)) }; } #[cfg(feature = "serialization-serde")] mod decoder; #[cfg(feature = "serialization-serde")] mod encoder; pub mod enums; #[cfg(feature = "transactions")] pub mod transaction; pub mod types; /// Metadata returned by `RegKey::query_info` #[derive(Debug, Default)] pub struct RegKeyMetadata { // pub Class: winapi::LPWSTR, // pub ClassLen: DWORD, pub sub_keys: DWORD, pub max_sub_key_len: DWORD, pub max_class_len: DWORD, pub values: DWORD, pub max_value_name_len: DWORD, pub max_value_len: DWORD, // pub SecurityDescriptor: DWORD, pub last_write_time: FILETIME, } impl RegKeyMetadata { /// Returns `last_write_time` field as `winapi::um::minwinbase::SYSTEMTIME` pub fn get_last_write_time_system(&self) -> SYSTEMTIME { let mut st: SYSTEMTIME = unsafe { ::std::mem::zeroed() }; unsafe { FileTimeToSystemTime(&self.last_write_time, &mut st); } st } /// Returns `last_write_time` field as `chrono::NaiveDateTime`. /// Part of `chrono` feature. #[cfg(feature = "chrono")] pub fn get_last_write_time_chrono(&self) -> chrono::NaiveDateTime { let st = self.get_last_write_time_system(); chrono::NaiveDate::from_ymd(st.wYear.into(), st.wMonth.into(), st.wDay.into()).and_hms( st.wHour.into(), st.wMinute.into(), st.wSecond.into(), ) } } /// Raw registry value #[derive(PartialEq)] pub struct RegValue { pub bytes: Vec, pub vtype: RegType, } macro_rules! format_reg_value { ($e:expr => $t:ident) => { match $t::from_reg_value($e) { Ok(val) => format!("{:?}", val), Err(_) => return Err(fmt::Error), } }; } impl fmt::Display for RegValue { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let f_val = match self.vtype { REG_SZ | REG_EXPAND_SZ | REG_MULTI_SZ => format_reg_value!(self => String), REG_DWORD => format_reg_value!(self => u32), REG_QWORD => format_reg_value!(self => u64), _ => format!("{:?}", self.bytes), //TODO: implement more types }; write!(f, "{}", f_val) } } impl fmt::Debug for RegValue { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "RegValue({:?}: {})", self.vtype, self) } } /// Handle of opened registry key #[derive(Debug)] pub struct RegKey { hkey: HKEY, } unsafe impl Send for RegKey {} impl RegKey { /// Open one of predefined keys: /// /// * `HKEY_CLASSES_ROOT` /// * `HKEY_CURRENT_USER` /// * `HKEY_LOCAL_MACHINE` /// * `HKEY_USERS` /// * `HKEY_PERFORMANCE_DATA` /// * `HKEY_PERFORMANCE_TEXT` /// * `HKEY_PERFORMANCE_NLSTEXT` /// * `HKEY_CURRENT_CONFIG` /// * `HKEY_DYN_DATA` /// * `HKEY_CURRENT_USER_LOCAL_SETTINGS` /// /// # Examples /// /// ```no_run /// # use winreg::RegKey; /// # use winreg::enums::*; /// let hklm = RegKey::predef(HKEY_LOCAL_MACHINE); /// ``` pub const fn predef(hkey: HKEY) -> RegKey { RegKey { hkey } } /// Load a registry hive from a file as an application hive. /// If `lock` is set to `true`, then the hive cannot be loaded again until /// it's unloaded (i.e. all keys from it go out of scope). /// /// # Examples /// /// ```no_run /// # use std::error::Error; /// # use winreg::RegKey; /// # use winreg::enums::*; /// # fn main() -> Result<(), Box> { /// let handle = RegKey::load_app_key("C:\\myhive.dat", false)?; /// # Ok(()) /// # } /// ``` pub fn load_app_key>(filename: N, lock: bool) -> io::Result { let options = if lock { winapi_reg::REG_PROCESS_APPKEY } else { 0 }; RegKey::load_app_key_with_flags(filename, enums::KEY_ALL_ACCESS, options) } /// Load a registry hive from a file as an application hive with desired /// permissions and options. If `options` is set to `REG_PROCESS_APPKEY`, /// then the hive cannot be loaded again until it's unloaded (i.e. all keys /// from it go out of scope). /// # Examples /// /// ```no_run /// # use std::error::Error; /// # use winreg::RegKey; /// # use winreg::enums::*; /// # fn main() -> Result<(), Box> { /// let handle = RegKey::load_app_key_with_flags("C:\\myhive.dat", KEY_READ, 0)?; /// # Ok(()) /// # } /// ``` pub fn load_app_key_with_flags>( filename: N, perms: winapi_reg::REGSAM, options: DWORD, ) -> io::Result { let c_filename = to_utf16(filename); let mut new_hkey: HKEY = ptr::null_mut(); match unsafe { winapi_reg::RegLoadAppKeyW(c_filename.as_ptr(), &mut new_hkey, perms, options, 0) as DWORD } { 0 => Ok(RegKey { hkey: new_hkey }), err => werr!(err), } } /// Return inner winapi HKEY of a key: /// /// # Examples /// /// ```no_run /// # use std::error::Error; /// # use winreg::RegKey; /// # use winreg::enums::*; /// # fn main() -> Result<(), Box> { /// let hklm = RegKey::predef(HKEY_LOCAL_MACHINE); /// let soft = hklm.open_subkey("SOFTWARE")?; /// let handle = soft.raw_handle(); /// # Ok(()) /// # } /// ``` pub const fn raw_handle(&self) -> HKEY { self.hkey } /// Open subkey with `KEY_READ` permissions. /// Will open another handle to itself if `path` is an empty string. /// To open with different permissions use `open_subkey_with_flags`. /// You can also use `create_subkey` to open with `KEY_ALL_ACCESS` permissions. /// /// # Examples /// /// ```no_run /// # use std::error::Error; /// # use winreg::RegKey; /// # use winreg::enums::*; /// # fn main() -> Result<(), Box> { /// let soft = RegKey::predef(HKEY_CURRENT_USER) /// .open_subkey("Software")?; /// # Ok(()) /// # } /// ``` pub fn open_subkey>(&self, path: P) -> io::Result { self.open_subkey_with_flags(path, enums::KEY_READ) } /// Open subkey with desired permissions. /// Will open another handle to itself if `path` is an empty string. /// /// # Examples /// /// ```no_run /// # use std::error::Error; /// # use winreg::RegKey; /// # use winreg::enums::*; /// # fn main() -> Result<(), Box> { /// let hklm = RegKey::predef(HKEY_LOCAL_MACHINE); /// hklm.open_subkey_with_flags("SOFTWARE\\Microsoft", KEY_READ)?; /// # Ok(()) /// # } /// ``` pub fn open_subkey_with_flags>( &self, path: P, perms: winapi_reg::REGSAM, ) -> io::Result { let c_path = to_utf16(path); let mut new_hkey: HKEY = ptr::null_mut(); match unsafe { winapi_reg::RegOpenKeyExW(self.hkey, c_path.as_ptr(), 0, perms, &mut new_hkey) as DWORD } { 0 => Ok(RegKey { hkey: new_hkey }), err => werr!(err), } } /// Part of `transactions` feature. #[cfg(feature = "transactions")] pub fn open_subkey_transacted>( &self, path: P, t: &Transaction, ) -> io::Result { self.open_subkey_transacted_with_flags(path, t, winnt::KEY_READ) } /// Part of `transactions` feature. #[cfg(feature = "transactions")] pub fn open_subkey_transacted_with_flags>( &self, path: P, t: &Transaction, perms: winapi_reg::REGSAM, ) -> io::Result { let c_path = to_utf16(path); let mut new_hkey: HKEY = ptr::null_mut(); match unsafe { winapi_reg::RegOpenKeyTransactedW( self.hkey, c_path.as_ptr(), 0, perms, &mut new_hkey, t.handle, ptr::null_mut(), ) as DWORD } { 0 => Ok(RegKey { hkey: new_hkey }), err => werr!(err), } } /// Create subkey (and all missing parent keys) /// and open it with `KEY_ALL_ACCESS` permissions. /// Will just open key if it already exists. /// If succeeds returns a tuple with the created subkey and its disposition, /// which can be `REG_CREATED_NEW_KEY` or `REG_OPENED_EXISTING_KEY`. /// Will open another handle to itself if `path` is an empty string. /// To create with different permissions use `create_subkey_with_flags`. /// /// # Examples /// /// ```no_run /// # use std::error::Error; /// # use winreg::RegKey; /// use winreg::enums::*; /// # fn main() -> Result<(), Box> { /// let hkcu = RegKey::predef(HKEY_CURRENT_USER); /// let (settings, disp) = hkcu.create_subkey("Software\\MyProduct\\Settings")?; /// /// match disp { /// REG_CREATED_NEW_KEY => println!("A new key has been created"), /// REG_OPENED_EXISTING_KEY => println!("An existing key has been opened") /// } /// # Ok(()) /// # } /// ``` pub fn create_subkey>(&self, path: P) -> io::Result<(RegKey, RegDisposition)> { self.create_subkey_with_flags(path, enums::KEY_ALL_ACCESS) } pub fn create_subkey_with_flags>( &self, path: P, perms: winapi_reg::REGSAM, ) -> io::Result<(RegKey, RegDisposition)> { let c_path = to_utf16(path); let mut new_hkey: HKEY = ptr::null_mut(); let mut disp_buf: DWORD = 0; match unsafe { winapi_reg::RegCreateKeyExW( self.hkey, c_path.as_ptr(), 0, ptr::null_mut(), winnt::REG_OPTION_NON_VOLATILE, perms, ptr::null_mut(), &mut new_hkey, &mut disp_buf, ) } { 0 => { let disp: RegDisposition = unsafe { transmute(disp_buf as u8) }; Ok((RegKey { hkey: new_hkey }, disp)) } err => werr!(err), } } /// Part of `transactions` feature. #[cfg(feature = "transactions")] pub fn create_subkey_transacted>( &self, path: P, t: &Transaction, ) -> io::Result<(RegKey, RegDisposition)> { self.create_subkey_transacted_with_flags(path, t, winnt::KEY_ALL_ACCESS) } /// Part of `transactions` feature. #[cfg(feature = "transactions")] pub fn create_subkey_transacted_with_flags>( &self, path: P, t: &Transaction, perms: winapi_reg::REGSAM, ) -> io::Result<(RegKey, RegDisposition)> { let c_path = to_utf16(path); let mut new_hkey: HKEY = ptr::null_mut(); let mut disp_buf: DWORD = 0; match unsafe { winapi_reg::RegCreateKeyTransactedW( self.hkey, c_path.as_ptr(), 0, ptr::null_mut(), winnt::REG_OPTION_NON_VOLATILE, perms, ptr::null_mut(), &mut new_hkey, &mut disp_buf, t.handle, ptr::null_mut(), ) as DWORD } { 0 => { let disp: RegDisposition = unsafe { transmute(disp_buf as u8) }; Ok((RegKey { hkey: new_hkey }, disp)) } err => werr!(err), } } /// Copy all the values and subkeys from `path` to `dest` key. /// WIll copy the content of `self` if `path` is an empty string. /// /// # Examples /// /// ```no_run /// # use std::error::Error; /// # use winreg::RegKey; /// # use winreg::enums::*; /// # fn main() -> Result<(), Box> { /// let hkcu = RegKey::predef(HKEY_CURRENT_USER); /// let src = hkcu.open_subkey_with_flags("Software\\MyProduct", KEY_READ)?; /// let (dst, dst_disp) = hkcu.create_subkey("Software\\MyProduct\\Section2")?; /// src.copy_tree("Section1", &dst)?; /// # Ok(()) /// # } /// ``` pub fn copy_tree>(&self, path: P, dest: &RegKey) -> io::Result<()> { let c_path = to_utf16(path); match unsafe { winapi_reg::RegCopyTreeW(self.hkey, c_path.as_ptr(), dest.hkey) } { 0 => Ok(()), err => werr!(err), } } pub fn query_info(&self) -> io::Result { let mut info: RegKeyMetadata = Default::default(); match unsafe { winapi_reg::RegQueryInfoKeyW( self.hkey, ptr::null_mut(), // Class: winapi::LPWSTR, ptr::null_mut(), // ClassLen: DWORD, ptr::null_mut(), // Reserved &mut info.sub_keys, &mut info.max_sub_key_len, &mut info.max_class_len, &mut info.values, &mut info.max_value_name_len, &mut info.max_value_len, ptr::null_mut(), // lpcbSecurityDescriptor: winapi::LPDWORD, &mut info.last_write_time, ) as DWORD } { 0 => Ok(info), err => werr!(err), } } /// Return an iterator over subkeys names. /// /// # Examples /// /// ```no_run /// # use winreg::RegKey; /// # use winreg::enums::*; /// println!("File extensions, registered in this system:"); /// for i in RegKey::predef(HKEY_CLASSES_ROOT) /// .enum_keys().map(|x| x.unwrap()) /// .filter(|x| x.starts_with(".")) /// { /// println!("{}", i); /// } /// ``` pub const fn enum_keys(&self) -> EnumKeys { EnumKeys { key: self, index: 0, } } /// Return an iterator over values. /// /// # Examples /// /// ```no_run /// # use std::error::Error; /// # use winreg::RegKey; /// # use winreg::enums::*; /// # fn main() -> Result<(), Box> { /// let system = RegKey::predef(HKEY_LOCAL_MACHINE) /// .open_subkey_with_flags("HARDWARE\\DESCRIPTION\\System", KEY_READ)?; /// for (name, value) in system.enum_values().map(|x| x.unwrap()) { /// println!("{} = {:?}", name, value); /// } /// # Ok(()) /// # } /// ``` pub const fn enum_values(&self) -> EnumValues { EnumValues { key: self, index: 0, } } /// Delete key. Key names are not case sensitive. /// Cannot delete if it has subkeys. /// Use `delete_subkey_all` for that. /// /// # Examples /// /// ```no_run /// # use std::error::Error; /// # use winreg::RegKey; /// # use winreg::enums::*; /// # fn main() -> Result<(), Box> { /// RegKey::predef(HKEY_CURRENT_USER) /// .delete_subkey(r"Software\MyProduct\History")?; /// # Ok(()) /// # } /// ``` pub fn delete_subkey>(&self, path: P) -> io::Result<()> { self.delete_subkey_with_flags(path, 0) } /// Delete key from the desired platform-specific view of the registry. /// Key names are not case sensitive. /// /// # Examples /// ```no_run /// # use std::error::Error; /// # use winreg::RegKey; /// # use winreg::enums::*; /// # fn main() -> Result<(), Box> { /// // delete the key from the 32-bit registry view /// RegKey::predef(HKEY_LOCAL_MACHINE) /// .delete_subkey_with_flags(r"Software\MyProduct\History", KEY_WOW64_32KEY)?; /// # Ok(()) /// # } /// ``` pub fn delete_subkey_with_flags>( &self, path: P, perms: winapi_reg::REGSAM, ) -> io::Result<()> { let c_path = to_utf16(path); match unsafe { winapi_reg::RegDeleteKeyExW( self.hkey, c_path.as_ptr(), // This parameter cannot be NULL. perms, 0, ) } { 0 => Ok(()), err => werr!(err), } } /// Part of `transactions` feature. #[cfg(feature = "transactions")] pub fn delete_subkey_transacted>( &self, path: P, t: &Transaction, ) -> io::Result<()> { self.delete_subkey_transacted_with_flags(path, t, 0) } /// Part of `transactions` feature. #[cfg(feature = "transactions")] pub fn delete_subkey_transacted_with_flags>( &self, path: P, t: &Transaction, perms: winapi_reg::REGSAM, ) -> io::Result<()> { let c_path = to_utf16(path); match unsafe { winapi_reg::RegDeleteKeyTransactedW( self.hkey, c_path.as_ptr(), // This parameter cannot be NULL. perms, 0, t.handle, ptr::null_mut(), ) } { 0 => Ok(()), err => werr!(err), } } /// Recursively delete subkey with all its subkeys and values. /// If `path` is an empty string, the subkeys and values of this key are deleted. /// /// # Examples /// /// ```no_run /// # use std::error::Error; /// # use winreg::RegKey; /// # use winreg::enums::*; /// # fn main() -> Result<(), Box> { /// RegKey::predef(HKEY_CURRENT_USER) /// .delete_subkey_all("Software\\MyProduct")?; /// # Ok(()) /// # } /// ``` pub fn delete_subkey_all>(&self, path: P) -> io::Result<()> { let c_path; let path_ptr = if path.as_ref().is_empty() { ptr::null() } else { c_path = to_utf16(path); c_path.as_ptr() }; match unsafe { winapi_reg::RegDeleteTreeW( self.hkey, path_ptr, //If this parameter is NULL, the subkeys and values of this key are deleted. ) as DWORD } { 0 => Ok(()), err => werr!(err), } } /// Get a value from registry and seamlessly convert it to the specified rust type /// with `FromRegValue` implemented (currently `String`, `u32` and `u64`). /// Will get the `Default` value if `name` is an empty string. /// /// # Examples /// /// ```no_run /// # use std::error::Error; /// # use winreg::RegKey; /// # use winreg::enums::*; /// # fn main() -> Result<(), Box> { /// let hkcu = RegKey::predef(HKEY_CURRENT_USER); /// let settings = hkcu.open_subkey("Software\\MyProduct\\Settings")?; /// let server: String = settings.get_value("server")?; /// let port: u32 = settings.get_value("port")?; /// # Ok(()) /// # } /// ``` pub fn get_value>(&self, name: N) -> io::Result { match self.get_raw_value(name) { Ok(ref val) => FromRegValue::from_reg_value(val), Err(err) => Err(err), } } /// Get raw bytes from registry value. /// Will get the `Default` value if `name` is an empty string. /// /// # Examples /// /// ```no_run /// # use std::error::Error; /// # use winreg::RegKey; /// # use winreg::enums::*; /// # fn main() -> Result<(), Box> { /// let hkcu = RegKey::predef(HKEY_CURRENT_USER); /// let settings = hkcu.open_subkey("Software\\MyProduct\\Settings")?; /// let data = settings.get_raw_value("data")?; /// println!("Bytes: {:?}", data.bytes); /// # Ok(()) /// # } /// ``` pub fn get_raw_value>(&self, name: N) -> io::Result { let c_name = to_utf16(name); let mut buf_len: DWORD = 2048; let mut buf_type: DWORD = 0; let mut buf: Vec = Vec::with_capacity(buf_len as usize); loop { match unsafe { winapi_reg::RegQueryValueExW( self.hkey, c_name.as_ptr() as *const u16, ptr::null_mut(), &mut buf_type, buf.as_mut_ptr() as LPBYTE, &mut buf_len, ) as DWORD } { 0 => { unsafe { buf.set_len(buf_len as usize); } // minimal check before transmute to RegType if buf_type > winnt::REG_QWORD { return werr!(winerror::ERROR_BAD_FILE_TYPE); } let t: RegType = unsafe { transmute(buf_type as u8) }; return Ok(RegValue { bytes: buf, vtype: t, }); } winerror::ERROR_MORE_DATA => { buf.reserve(buf_len as usize); } err => return werr!(err), } } } /// Seamlessly convert a value from a rust type and write it to the registry value /// with `ToRegValue` trait implemented (currently `String`, `&str`, `u32` and `u64`). /// Will set the `Default` value if `name` is an empty string. /// /// # Examples /// /// ```no_run /// # use std::error::Error; /// # use winreg::RegKey; /// # use winreg::enums::*; /// # fn main() -> Result<(), Box> { /// let hkcu = RegKey::predef(HKEY_CURRENT_USER); /// let (settings, disp) = hkcu.create_subkey("Software\\MyProduct\\Settings")?; /// settings.set_value("server", &"www.example.com")?; /// settings.set_value("port", &8080u32)?; /// # Ok(()) /// # } /// ``` pub fn set_value>(&self, name: N, value: &T) -> io::Result<()> { self.set_raw_value(name, &value.to_reg_value()) } /// Write raw bytes from `RegValue` struct to a registry value. /// Will set the `Default` value if `name` is an empty string. /// /// # Examples /// /// ```no_run /// # use std::error::Error; /// use winreg::{RegKey, RegValue}; /// use winreg::enums::*; /// # fn main() -> Result<(), Box> { /// let hkcu = RegKey::predef(HKEY_CURRENT_USER); /// let settings = hkcu.open_subkey("Software\\MyProduct\\Settings")?; /// let bytes: Vec = vec![1, 2, 3, 5, 8, 13, 21, 34, 55, 89]; /// let data = RegValue{ vtype: REG_BINARY, bytes: bytes}; /// settings.set_raw_value("data", &data)?; /// println!("Bytes: {:?}", data.bytes); /// # Ok(()) /// # } /// ``` pub fn set_raw_value>(&self, name: N, value: &RegValue) -> io::Result<()> { let c_name = to_utf16(name); let t = value.vtype.clone() as DWORD; match unsafe { winapi_reg::RegSetValueExW( self.hkey, c_name.as_ptr(), 0, t, value.bytes.as_ptr() as *const BYTE, value.bytes.len() as u32, ) as DWORD } { 0 => Ok(()), err => werr!(err), } } /// Delete specified value from registry. /// Will delete the `Default` value if `name` is an empty string. /// /// # Examples /// /// ```no_run /// # use std::error::Error; /// # use winreg::RegKey; /// # use winreg::enums::*; /// # fn main() -> Result<(), Box> { /// let hkcu = RegKey::predef(HKEY_CURRENT_USER); /// let settings = hkcu.open_subkey("Software\\MyProduct\\Settings")?; /// settings.delete_value("data")?; /// # Ok(()) /// # } /// ``` pub fn delete_value>(&self, name: N) -> io::Result<()> { let c_name = to_utf16(name); match unsafe { winapi_reg::RegDeleteValueW(self.hkey, c_name.as_ptr()) as DWORD } { 0 => Ok(()), err => werr!(err), } } /// Save `Encodable` type to a registry key. /// Part of `serialization-serde` feature. /// /// # Examples /// /// ```no_run /// # use std::error::Error; /// #[macro_use] /// extern crate serde_derive; /// extern crate winreg; /// use winreg::RegKey; /// use winreg::enums::*; /// /// #[derive(Serialize)] /// struct Rectangle{ /// x: u32, /// y: u32, /// w: u32, /// h: u32, /// } /// /// #[derive(Serialize)] /// struct Settings{ /// current_dir: String, /// window_pos: Rectangle, /// show_in_tray: bool, /// } /// /// # fn main() -> Result<(), Box> { /// let s: Settings = Settings{ /// current_dir: "C:\\".to_owned(), /// window_pos: Rectangle{ x:200, y: 100, w: 800, h: 500 }, /// show_in_tray: false, /// }; /// let s_key = RegKey::predef(HKEY_CURRENT_USER) /// .open_subkey("Software\\MyProduct\\Settings")?; /// s_key.encode(&s)?; /// # Ok(()) /// # } /// ``` #[cfg(feature = "serialization-serde")] pub fn encode(&self, value: &T) -> encoder::EncodeResult<()> { let mut encoder = encoder::Encoder::from_key(self)?; value.serialize(&mut encoder)?; encoder.commit() } /// Load `Decodable` type from a registry key. /// Part of `serialization-serde` feature. /// /// # Examples /// /// ```no_run /// # use std::error::Error; /// #[macro_use] /// extern crate serde_derive; /// extern crate winreg; /// use winreg::RegKey; /// use winreg::enums::*; /// /// #[derive(Deserialize)] /// struct Rectangle{ /// x: u32, /// y: u32, /// w: u32, /// h: u32, /// } /// /// #[derive(Deserialize)] /// struct Settings{ /// current_dir: String, /// window_pos: Rectangle, /// show_in_tray: bool, /// } /// /// # fn main() -> Result<(), Box> { /// let s_key = RegKey::predef(HKEY_CURRENT_USER) /// .open_subkey("Software\\MyProduct\\Settings")?; /// let s: Settings = s_key.decode()?; /// # Ok(()) /// # } /// ``` #[cfg(feature = "serialization-serde")] pub fn decode<'de, T: serde::Deserialize<'de>>(&self) -> decoder::DecodeResult { let mut decoder = decoder::Decoder::from_key(self)?; T::deserialize(&mut decoder) } fn close_(&mut self) -> io::Result<()> { // don't try to close predefined keys if self.hkey >= enums::HKEY_CLASSES_ROOT { return Ok(()); }; match unsafe { winapi_reg::RegCloseKey(self.hkey) as DWORD } { 0 => Ok(()), err => werr!(err), } } fn enum_key(&self, index: DWORD) -> Option> { let mut name_len = 2048; #[allow(clippy::unnecessary_cast)] let mut name = [0 as WCHAR; 2048]; match unsafe { winapi_reg::RegEnumKeyExW( self.hkey, index, name.as_mut_ptr(), &mut name_len, ptr::null_mut(), // reserved ptr::null_mut(), // lpClass: LPWSTR, ptr::null_mut(), // lpcClass: LPDWORD, ptr::null_mut(), // lpftLastWriteTime: PFILETIME, ) as DWORD } { 0 => match String::from_utf16(&name[..name_len as usize]) { Ok(s) => Some(Ok(s)), Err(_) => Some(werr!(winerror::ERROR_INVALID_BLOCK)), }, winerror::ERROR_NO_MORE_ITEMS => None, err => Some(werr!(err)), } } fn enum_value(&self, index: DWORD) -> Option> { let mut name_len = 2048; #[allow(clippy::unnecessary_cast)] let mut name = [0 as WCHAR; 2048]; let mut buf_len: DWORD = 2048; let mut buf_type: DWORD = 0; let mut buf: Vec = Vec::with_capacity(buf_len as usize); loop { match unsafe { winapi_reg::RegEnumValueW( self.hkey, index, name.as_mut_ptr(), &mut name_len, ptr::null_mut(), // reserved &mut buf_type, buf.as_mut_ptr() as LPBYTE, &mut buf_len, ) as DWORD } { 0 => { let name = match String::from_utf16(&name[..name_len as usize]) { Ok(s) => s, Err(_) => return Some(werr!(winerror::ERROR_INVALID_DATA)), }; unsafe { buf.set_len(buf_len as usize); } // minimal check before transmute to RegType if buf_type > winnt::REG_QWORD { return Some(werr!(winerror::ERROR_BAD_FILE_TYPE)); } let t: RegType = unsafe { transmute(buf_type as u8) }; let value = RegValue { bytes: buf, vtype: t, }; return Some(Ok((name, value))); } winerror::ERROR_MORE_DATA => { name_len += 1; //for NULL char buf.reserve(buf_len as usize); } winerror::ERROR_NO_MORE_ITEMS => return None, err => return Some(werr!(err)), } } } } impl Drop for RegKey { fn drop(&mut self) { self.close_().unwrap_or(()); } } /// Iterator over subkeys names pub struct EnumKeys<'key> { key: &'key RegKey, index: DWORD, } impl<'key> Iterator for EnumKeys<'key> { type Item = io::Result; fn next(&mut self) -> Option> { match self.key.enum_key(self.index) { v @ Some(_) => { self.index += 1; v } e @ None => e, } } fn nth(&mut self, n: usize) -> Option { self.index += n as DWORD; self.next() } } /// Iterator over values pub struct EnumValues<'key> { key: &'key RegKey, index: DWORD, } impl<'key> Iterator for EnumValues<'key> { type Item = io::Result<(String, RegValue)>; fn next(&mut self) -> Option> { match self.key.enum_value(self.index) { v @ Some(_) => { self.index += 1; v } e @ None => e, } } fn nth(&mut self, n: usize) -> Option { self.index += n as DWORD; self.next() } } fn to_utf16>(s: P) -> Vec { s.as_ref() .encode_wide() .chain(Some(0).into_iter()) .collect() } fn v16_to_v8(v: &[u16]) -> Vec { unsafe { slice::from_raw_parts(v.as_ptr() as *const u8, v.len() * 2).to_vec() } }