winreg-0.6.0/.editorconfig000064400000000000000000000003011337334010300136420ustar0000000000000000root = true [*] charset = utf-8 end_of_line = lf trim_trailing_whitespace = true insert_final_newline = true indent_style = space indent_size = 4 [*.yml] indent_style = space indent_size = 2 winreg-0.6.0/.gitattributes000064400000000000000000000000231337334010300140610ustar0000000000000000* text=auto eol=lf winreg-0.6.0/.gitignore000064400000000000000000000000221337334010300131550ustar0000000000000000target Cargo.lock winreg-0.6.0/appveyor.yml000064400000000000000000000012041337534710700135750ustar0000000000000000version: 0.6.{build} pull_requests: do_not_increment_build_number: true os: Visual Studio 2015 environment: matrix: - TARGET: x86_64-pc-windows-gnu CHANNEL: stable - TARGET: x86_64-pc-windows-msvc CHANNEL: stable - TARGET: i686-pc-windows-gnu CHANNEL: stable - TARGET: i686-pc-windows-msvc CHANNEL: stable install: - curl -sSf -o rustup-init.exe https://win.rustup.rs - rustup-init.exe --default-host %TARGET% --default-toolchain %CHANNEL% -y - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin - rustc -Vv - cargo -V build: false test_script: - cargo test --features=serialization-serde winreg-0.6.0/Cargo.toml.orig000064400000000000000000000022151337534310100140650ustar0000000000000000[package] name = "winreg" version = "0.6.0" authors = ["Igor Shaula "] license = "MIT" description = "Rust bindings to MS Windows Registry API" repository = "https://github.com/gentoo90/winreg-rs" documentation = "https://gentoo90.github.io/winreg-rs/v0.6.0/winreg" readme = "README.md" keywords = ["Windows", "WinSDK", "Registry"] categories = ["api-bindings", "os::windows-apis"] [dependencies] winapi = { version = "0.3", features = ["minwindef", "winerror", "winnt", "winreg", "handleapi"] } serde = { version = "1", optional = true } clippy = { version = "^0", optional = true } [dev-dependencies] rand = "0.3" serde_derive = "1" [features] transactions = ["winapi/ktmw32"] serialization-serde = ["transactions", "serde"] [[example]] name = "basic_usage" [[example]] name = "enum" [[example]] name = "transactions" required-features = ["transactions"] [[example]] name = "serialization" required-features = ["serialization-serde"] [[example]] name = "installed_apps" required-features = ["serialization-serde"] [package.metadata.docs.rs] features = ["transactions", "serialization-serde"] default-target = "x86_64-pc-windows-msvc" winreg-0.6.0/Cargo.toml0000644000000033050000000000000103700ustar00# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g. crates.io) dependencies # # If you believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're # editing this file be aware that the upstream Cargo.toml # will likely look very different (and much more reasonable) [package] name = "winreg" version = "0.6.0" authors = ["Igor Shaula "] description = "Rust bindings to MS Windows Registry API" documentation = "https://gentoo90.github.io/winreg-rs/v0.6.0/winreg" readme = "README.md" keywords = ["Windows", "WinSDK", "Registry"] categories = ["api-bindings", "os::windows-apis"] license = "MIT" repository = "https://github.com/gentoo90/winreg-rs" [package.metadata.docs.rs] default-target = "x86_64-pc-windows-msvc" features = ["transactions", "serialization-serde"] [[example]] name = "basic_usage" [[example]] name = "enum" [[example]] name = "transactions" required-features = ["transactions"] [[example]] name = "serialization" required-features = ["serialization-serde"] [[example]] name = "installed_apps" required-features = ["serialization-serde"] [dependencies.clippy] version = "^0" optional = true [dependencies.serde] version = "1" optional = true [dependencies.winapi] version = "0.3" features = ["minwindef", "winerror", "winnt", "winreg", "handleapi"] [dev-dependencies.rand] version = "0.3" [dev-dependencies.serde_derive] version = "1" [features] serialization-serde = ["transactions", "serde"] transactions = ["winapi/ktmw32"] winreg-0.6.0/examples/basic_usage.rs000064400000000000000000000037271337433537500156550ustar0000000000000000// Copyright 2015, Igor Shaula // Licensed under the MIT License . This file // may not be copied, modified, or distributed // except according to those terms. extern crate winreg; use std::path::Path; use std::io; use winreg::RegKey; use winreg::enums::*; 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); 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("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(()) } winreg-0.6.0/examples/enum.rs000064400000000000000000000014151337433537500143440ustar0000000000000000// Copyright 2015, Igor Shaula // Licensed under the MIT License . This file // may not be copied, modified, or distributed // except according to those terms. 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(()) } winreg-0.6.0/examples/installed_apps.rs000064400000000000000000000023111337334010300163560ustar0000000000000000// Copyright 2017, Igor Shaula // Licensed under the MIT License . This file // may not be copied, modified, or distributed // except according to those terms. #[macro_use] extern crate serde_derive; extern crate winreg; use winreg::enums::*; use std::collections::HashMap; use std::fmt; #[allow(non_snake_case)] #[derive(Debug, Serialize, Deserialize)] struct InstalledApp { DisplayName: Option, DisplayVersion: Option, UninstallString: Option } macro_rules! str_from_opt { ($s:expr) => { $s.as_ref().map(|x| &**x).unwrap_or("") } } impl fmt::Display for InstalledApp { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}-{}", str_from_opt!(self.DisplayName), str_from_opt!(self.DisplayVersion)) } } fn main() { let hklm = winreg::RegKey::predef(HKEY_LOCAL_MACHINE); let uninstall_key = hklm.open_subkey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall") .expect("key is missing"); let apps: HashMap = uninstall_key.decode().expect("deserialization failed"); for (_k, v) in &apps { println!("{}", v); } } winreg-0.6.0/examples/serialization.rs000064400000000000000000000034351337534744200162600ustar0000000000000000// Copyright 2015, Igor Shaula // Licensed under the MIT License . This file // may not be copied, modified, or distributed // except according to those terms. #[macro_use] extern crate serde_derive; extern crate winreg; use std::error::Error; use winreg::enums::*; #[derive(Debug, Serialize, Deserialize, PartialEq)] struct Coords { x: u32, y: u32, } #[derive(Debug, Serialize, Deserialize, PartialEq)] struct Size { w: u32, h: u32, } #[derive(Debug, Serialize, Deserialize, PartialEq)] struct Rectangle { coords: Coords, size: Size, } #[derive(Debug, Serialize, Deserialize, PartialEq)] struct Test { t_bool: bool, t_u8: u8, t_u16: u16, t_u32: u32, t_u64: u64, t_usize: usize, t_struct: Rectangle, t_string: String, t_i8: i8, t_i16: i16, t_i32: i32, t_i64: i64, t_isize: isize, t_f64: f64, t_f32: f32, // t_char: char, } fn main() -> Result<(), Box> { let hkcu = winreg::RegKey::predef(HKEY_CURRENT_USER); let (key, _disp) = hkcu.create_subkey("Software\\RustEncode")?; let v1 = Test{ t_bool: false, t_u8: 127, t_u16: 32768, t_u32: 123456789, t_u64: 123456789101112, t_usize: 1234567891, t_struct: Rectangle{ coords: Coords{ x: 55, y: 77 }, size: Size{ w: 500, h: 300 }, }, t_string: "test 123!".to_owned(), t_i8: -123, t_i16: -2049, t_i32: 20100, t_i64: -12345678910, t_isize: -1234567890, t_f64: -0.01, t_f32: 3.14, // t_char: 'a', }; key.encode(&v1)?; let v2: Test = key.decode()?; println!("Decoded {:?}", v2); println!("Equal to encoded: {:?}", v1 == v2); Ok(()) } winreg-0.6.0/examples/transactions.rs000064400000000000000000000021671337433537500161150ustar0000000000000000// Copyright 2015, Igor Shaula // Licensed under the MIT License . This file // may not be copied, modified, or distributed // except according to those terms. extern crate winreg; use std::io; use winreg::RegKey; use winreg::enums::*; use winreg::transaction::Transaction; fn main() -> io::Result<()> { let t = Transaction::new()?; let hkcu = RegKey::predef(HKEY_CURRENT_USER); let (key, _disp) = hkcu.create_subkey_transacted("Software\\RustTransaction", &t)?; key.set_value("TestQWORD", &1234567891011121314u64)?; key.set_value("TestDWORD", &1234567890u32)?; println!("Commit transaction? [y/N]:"); let mut input = String::new(); io::stdin().read_line(&mut input)?; input = input.trim_right().to_owned(); if input == "y" || input == "Y" { t.commit()?; println!("Transaction committed."); } else { // this is optional, if transaction wasn't committed, // it will be rolled back on disposal t.rollback()?; println!("Transaction wasn't committed, it will be rolled back."); } Ok(()) } winreg-0.6.0/LICENSE000064400000000000000000000020371337334010300122020ustar0000000000000000Copyright (c) 2015 Igor Shaula Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. winreg-0.6.0/README.md000064400000000000000000000202131337535115600124640ustar0000000000000000winreg [![Crates.io](https://img.shields.io/crates/v/winreg.svg)](https://crates.io/crates/winreg) [![Build status](https://ci.appveyor.com/api/projects/status/f3lwrt67ghrf5omd?svg=true)](https://ci.appveyor.com/project/gentoo90/winreg-rs) ====== Rust bindings to MS Windows Registry API. Work in progress. Current features: * Basic registry operations: * open/create/delete keys * read and write values * seamless conversion between `REG_*` types and rust primitives * `String` and `OsString` <= `REG_SZ`, `REG_EXPAND_SZ` or `REG_MULTI_SZ` * `String`, `&str` and `OsStr` => `REG_SZ` * `u32` <=> `REG_DWORD` * `u64` <=> `REG_QWORD` * Iteration through key names and through values * Transactions * Transacted serialization of rust types into/from registry (only primitives and structures for now) ## Usage ### Basic usage ```toml # Cargo.toml [dependencies] winreg = "0.6" ``` ```rust extern crate winreg; use std::path::Path; use std::io; use winreg::RegKey; use winreg::enums::*; 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); 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("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 ```rust 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(()) } ``` ### Transactions ```toml # Cargo.toml [dependencies] winreg = { version = "0.6", features = ["transactions"] } ``` ```rust extern crate winreg; use std::io; use winreg::RegKey; use winreg::enums::*; use winreg::transaction::Transaction; fn main() -> io::Result<()> { let t = Transaction::new()?; let hkcu = RegKey::predef(HKEY_CURRENT_USER); let (key, _disp) = hkcu.create_subkey_transacted("Software\\RustTransaction", &t)?; key.set_value("TestQWORD", &1234567891011121314u64)?; key.set_value("TestDWORD", &1234567890u32)?; println!("Commit transaction? [y/N]:"); let mut input = String::new(); io::stdin().read_line(&mut input)?; input = input.trim_right().to_owned(); if input == "y" || input == "Y" { t.commit()?; println!("Transaction committed."); } else { // this is optional, if transaction wasn't committed, // it will be rolled back on disposal t.rollback()?; println!("Transaction wasn't committed, it will be rolled back."); } Ok(()) } ``` ### Serialization ```toml # Cargo.toml [dependencies] winreg = { version = "0.6", features = ["serialization-serde"] } serde = "1" serde_derive = "1" ``` ```rust #[macro_use] extern crate serde_derive; extern crate winreg; use std::error::Error; use winreg::enums::*; #[derive(Debug, Serialize, Deserialize, PartialEq)] struct Coords { x: u32, y: u32, } #[derive(Debug, Serialize, Deserialize, PartialEq)] struct Size { w: u32, h: u32, } #[derive(Debug, Serialize, Deserialize, PartialEq)] struct Rectangle { coords: Coords, size: Size, } #[derive(Debug, Serialize, Deserialize, PartialEq)] struct Test { t_bool: bool, t_u8: u8, t_u16: u16, t_u32: u32, t_u64: u64, t_usize: usize, t_struct: Rectangle, t_string: String, t_i8: i8, t_i16: i16, t_i32: i32, t_i64: i64, t_isize: isize, t_f64: f64, t_f32: f32, } fn main() -> Result<(), Box> { let hkcu = winreg::RegKey::predef(HKEY_CURRENT_USER); let (key, _disp) = hkcu.create_subkey("Software\\RustEncode")?; let v1 = Test{ t_bool: false, t_u8: 127, t_u16: 32768, t_u32: 123456789, t_u64: 123456789101112, t_usize: 1234567891, t_struct: Rectangle{ coords: Coords{ x: 55, y: 77 }, size: Size{ w: 500, h: 300 }, }, t_string: "test 123!".to_owned(), t_i8: -123, t_i16: -2049, t_i32: 20100, t_i64: -12345678910, t_isize: -1234567890, t_f64: -0.01, t_f32: 3.14, }; key.encode(&v1)?; let v2: Test = key.decode()?; println!("Decoded {:?}", v2); println!("Equal to encoded: {:?}", v1 == v2); Ok(()) } ``` ## Changelog ### 0.6.0 * Breaking change: `create_subkey`, `create_subkey_with_flags`, `create_subkey_transacted` and `create_subkey_transacted_with_flags` now return a tuple which contains the subkey and its disposition which can be `REG_CREATED_NEW_KEY` or `REG_OPENED_EXISTING_KEY` ([#21](https://github.com/gentoo90/winreg-rs/issues/21)). * Examples fixed to not use `unwrap` according to [Rust API guidelines](https://rust-lang-nursery.github.io/api-guidelines/documentation.html#examples-use--not-try-not-unwrap-c-question-mark). ### 0.5.1 * Reexport `HKEY` ([#15](https://github.com/gentoo90/winreg-rs/issues/15)). * Add `raw_handle` method ([#18](https://github.com/gentoo90/winreg-rs/pull/18)). ### 0.5.0 * Breaking change: `open_subkey` now opens a key with readonly permissions. Use `create_subkey` or `open_subkey_with_flags` to open with read-write permissins. * Breaking change: features `transactions` and `serialization-serde` are now disabled by default. * Breaking change: serialization now uses `serde` instead of `rustc-serialize`. * `winapi` updated to `0.3`. * Documentation fixes ([#14](https://github.com/gentoo90/winreg-rs/pull/14)) ### 0.4.0 * Make transactions and serialization otional features * Update dependensies + minor fixes ([#12](https://github.com/gentoo90/winreg-rs/pull/12)) ### 0.3.5 * Implement `FromRegValue` for `OsString` and `ToRegValue` for `OsStr` ([#8](https://github.com/gentoo90/winreg-rs/issues/8)) * Minor fixes ### 0.3.4 * Add `copy_tree` method to `RegKey` * Now checked with [rust-clippy](https://github.com/Manishearth/rust-clippy) * no more `unwrap`s * replaced `to_string` with `to_owned` * Fix: reading strings longer than 2048 characters ([#6](https://github.com/gentoo90/winreg-rs/pull/6)) ### 0.3.3 * Fix: now able to read values longer than 2048 bytes ([#3](https://github.com/gentoo90/winreg-rs/pull/3)) ### 0.3.2 * Fix: `FromRegValue` trait now requires `Sized` (fixes build with rust 1.4) ### 0.3.1 * Fix: bump `winapi` version to fix build ### 0.3.0 * Add transactions support and make serialization transacted * Breaking change: use `std::io::{Error,Result}` instead of own `RegError` and `RegResult` winreg-0.6.0/src/decoder/mod.rs000064400000000000000000000052411337334010300145160ustar0000000000000000// Copyright 2017, Igor Shaula // Licensed under the MIT License . This file // may not be copied, modified, or distributed // except according to those terms. use std::io; use std::fmt; use std::error::Error; use winapi::shared::minwindef::DWORD; use super::{RegKey}; use super::enums::*; macro_rules! read_value{ ($s:ident) => ( match mem::replace(&mut $s.f_name, None) { Some(ref s) => { $s.key.get_value(s) .map_err(DecoderError::IoError) }, None => Err(DecoderError::NoFieldName) } ) } macro_rules! parse_string{ ($s:ident) => ({ let s: String = read_value!($s)?; s.parse().map_err(|e| DecoderError::ParseError(format!("{:?}", e))) }) } macro_rules! no_impl { ($e:expr) => ( Err(DecoderError::DecodeNotImplemented($e.to_owned())) ) } #[cfg(feature = "serialization-serde")] mod serialization_serde; #[derive(Debug)] pub enum DecoderError{ DecodeNotImplemented(String), DeserializerError(String), IoError(io::Error), ParseError(String), NoFieldName, } impl fmt::Display for DecoderError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{:?}", self) } } impl Error for DecoderError { fn description(&self) -> &str { use self::DecoderError::*; match *self { DecodeNotImplemented(ref s) | DeserializerError(ref s) | ParseError(ref s) => s, IoError(ref e) => e.description(), NoFieldName => "No field name" } } } impl From for DecoderError { fn from(err: io::Error) -> DecoderError { DecoderError::IoError(err) } } pub type DecodeResult = Result; #[derive(Debug)] enum DecoderReadingState { WaitingForKey, WaitingForValue, } #[derive(Debug)] enum DecoderEnumerationState { EnumeratingKeys(DWORD), EnumeratingValues(DWORD), } #[derive(Debug)] pub struct Decoder { key: RegKey, f_name: Option, reading_state: DecoderReadingState, enumeration_state: DecoderEnumerationState, } const DECODER_SAM: DWORD = KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS; impl Decoder { pub fn from_key(key: &RegKey) -> DecodeResult { key.open_subkey_with_flags("", DECODER_SAM) .map(Decoder::new) .map_err(DecoderError::IoError) } fn new(key: RegKey) -> Decoder { Decoder{ key: key, f_name: None, reading_state: DecoderReadingState::WaitingForKey, enumeration_state: DecoderEnumerationState::EnumeratingKeys(0) } } } winreg-0.6.0/src/decoder/serialization_serde.rs000064400000000000000000000206241337334010300200000ustar0000000000000000// Copyright 2017, Igor Shaula // Licensed under the MIT License . This file // may not be copied, modified, or distributed // except according to those terms. use std::mem; use std::fmt; use serde::de::*; use super::{DecoderError, DecodeResult, DecoderReadingState, DecoderEnumerationState, Decoder, DECODER_SAM}; use super::super::FromRegValue; impl Error for DecoderError { fn custom(msg: T) -> Self { DecoderError::DeserializerError(format!("{}", msg)) } } impl<'de, 'a> Deserializer<'de> for &'a mut Decoder { type Error = DecoderError; fn deserialize_any(self, visitor: V) -> DecodeResult where V: Visitor<'de> { use self::DecoderEnumerationState::*; match self.enumeration_state { EnumeratingKeys(..) => no_impl!("deserialize_any for keys"), EnumeratingValues(..) => { let s = self.f_name.as_ref().ok_or(DecoderError::NoFieldName)?; let v = self.key.get_raw_value(s)?; use RegType::*; match v.vtype { REG_SZ | REG_EXPAND_SZ | REG_MULTI_SZ => visitor.visit_string(String::from_reg_value(&v)?), REG_DWORD => visitor.visit_u32(u32::from_reg_value(&v)?), REG_QWORD => visitor.visit_u64(u64::from_reg_value(&v)?), _ => Err(DecoderError::DecodeNotImplemented("value type deserialization not implemented".to_owned())) } } } } fn deserialize_bool(self, visitor: V) -> DecodeResult where V: Visitor<'de> { visitor.visit_bool(read_value!(self).map(|v: u32| v > 0)?) } fn deserialize_u8(self, visitor: V) -> DecodeResult where V: Visitor<'de> { self.deserialize_u32(visitor) } fn deserialize_u16(self, visitor: V) -> DecodeResult where V: Visitor<'de> { self.deserialize_u32(visitor) } fn deserialize_u32(self, visitor: V) -> DecodeResult where V: Visitor<'de> { visitor.visit_u32(read_value!(self)?) } fn deserialize_u64(self, visitor: V) -> DecodeResult where V: Visitor<'de> { visitor.visit_u64(read_value!(self)?) } fn deserialize_i8(self, visitor: V) -> DecodeResult where V: Visitor<'de> { visitor.visit_i8(parse_string!(self)?) } fn deserialize_i16(self, visitor: V) -> DecodeResult where V: Visitor<'de> { visitor.visit_i16(parse_string!(self)?) } fn deserialize_i32(self, visitor: V) -> DecodeResult where V: Visitor<'de> { visitor.visit_i32(parse_string!(self)?) } fn deserialize_i64(self, visitor: V) -> DecodeResult where V: Visitor<'de> { visitor.visit_i64(parse_string!(self)?) } fn deserialize_f32(self, visitor: V) -> DecodeResult where V: Visitor<'de> { visitor.visit_f32(parse_string!(self)?) } fn deserialize_f64(self, visitor: V) -> DecodeResult where V: Visitor<'de> { visitor.visit_f64(parse_string!(self)?) } fn deserialize_char(self, _visitor: V) -> DecodeResult where V: Visitor<'de> { no_impl!("deserialize_char") } fn deserialize_str(self, _visitor: V) -> DecodeResult where V: Visitor<'de> { no_impl!("deserialize_str") } fn deserialize_string(self, visitor: V) -> DecodeResult where V: Visitor<'de> { use self::DecoderReadingState::*; match self.reading_state { WaitingForKey => { let s = self.f_name.as_ref().ok_or(DecoderError::NoFieldName)?; visitor.visit_string(s.clone()) } WaitingForValue => visitor.visit_string(read_value!(self)?) } } fn deserialize_bytes(self, _visitor: V) -> DecodeResult where V: Visitor<'de> { no_impl!("deserialize_bytes") } fn deserialize_byte_buf(self, _visitor: V) -> DecodeResult where V: Visitor<'de> { no_impl!("deserialize_byte_buf") } fn deserialize_option(self, visitor: V) -> DecodeResult where V: Visitor<'de> { let v = { let s = self.f_name.as_ref().ok_or(DecoderError::NoFieldName)?; self.key.get_raw_value(s) }; match v { Ok(..) => visitor.visit_some(&mut *self), Err(..) => visitor.visit_none() } } fn deserialize_unit(self, _visitor: V) -> DecodeResult where V: Visitor<'de> { no_impl!("deserialize_unit") } fn deserialize_unit_struct(self, _name: &'static str, _visitor: V) -> DecodeResult where V: Visitor<'de> { no_impl!("deserialize_unit_struct") } fn deserialize_newtype_struct(self, _name: &'static str, _visitor: V) -> DecodeResult where V: Visitor<'de> { no_impl!("deserialize_newtype_struct") } fn deserialize_seq(self, _visitor: V) -> DecodeResult where V: Visitor<'de> { no_impl!("deserialize_seq") } fn deserialize_tuple(self, _len: usize, _visitor: V) -> DecodeResult where V: Visitor<'de> { no_impl!("deserialize_tuple") } fn deserialize_tuple_struct(self, _name: &'static str, _len: usize, _visitor: V) -> DecodeResult where V: Visitor<'de> { no_impl!("deserialize_tuple_struct") } fn deserialize_map(self, visitor: V) -> DecodeResult where V: Visitor<'de> { visitor.visit_map(self) } fn deserialize_struct(self, _name: &'static str, _fields: &'static [&'static str], visitor: V) -> DecodeResult where V: Visitor<'de> { visitor.visit_map(self) } fn deserialize_identifier(self, visitor: V) -> DecodeResult where V: Visitor<'de> { self.deserialize_string(visitor) } fn deserialize_enum(self, _name: &'static str, _variants: &'static [&'static str], _visitor: V) -> DecodeResult where V: Visitor<'de> { no_impl!("deserialize_enum") } fn deserialize_ignored_any(self, visitor: V) -> DecodeResult where V: Visitor<'de> { self.deserialize_any(visitor) } } impl<'de, 'a> MapAccess<'de> for Decoder { type Error = DecoderError; fn next_key_seed(&mut self, seed: K) -> Result, Self::Error> where K: DeserializeSeed<'de> { self.reading_state = DecoderReadingState::WaitingForKey; use self::DecoderEnumerationState::*; match self.enumeration_state { EnumeratingKeys(index) => { match self.key.enum_key(index) { Some(res) => { self.f_name = Some(res?); self.enumeration_state = EnumeratingKeys(index + 1); seed.deserialize(&mut *self).map(Some) } None => { self.enumeration_state = EnumeratingValues(0); self.next_key_seed(seed) } } } EnumeratingValues(index) => { let next_value = self.key.enum_value(index); match next_value { Some(res) => { self.f_name = Some(res?.0); self.enumeration_state = EnumeratingValues(index + 1); seed.deserialize(&mut *self).map(Some) } None => Ok(None), } } } } fn next_value_seed(&mut self, seed: V) -> Result where V: DeserializeSeed<'de> { self.reading_state = DecoderReadingState::WaitingForValue; use self::DecoderEnumerationState::*; match self.enumeration_state { EnumeratingKeys(..) => { let f_name = self.f_name.as_ref().ok_or(DecoderError::NoFieldName)?; match self.key.open_subkey_with_flags(f_name, DECODER_SAM) { Ok(subkey) => { let mut nested = Decoder::new(subkey); seed.deserialize(&mut nested) } Err(err) => Err(DecoderError::IoError(err)), } }, EnumeratingValues(..) => { seed.deserialize(&mut *self) } } } } winreg-0.6.0/src/encoder/mod.rs000064400000000000000000000050161337334010300145300ustar0000000000000000// Copyright 2017, Igor Shaula // Licensed under the MIT License . This file // may not be copied, modified, or distributed // except according to those terms. use std::io; use std::fmt; use std::error::Error; use winapi::shared::minwindef::DWORD; use super::RegKey; use super::enums::*; use super::transaction::Transaction; use self::EncoderState::*; macro_rules! emit_value{ ($s:ident, $v:ident) => ( match mem::replace(&mut $s.state, Start) { NextKey(ref s) => { $s.keys[$s.keys.len()-1].set_value(s, &$v) .map_err(EncoderError::IoError) }, Start => Err(EncoderError::NoFieldName) } ) } macro_rules! no_impl { ($e:expr) => ( Err(EncoderError::EncodeNotImplemented($e.to_owned())) ) } #[cfg(feature = "serialization-serde")] mod serialization_serde; #[derive(Debug)] pub enum EncoderError{ EncodeNotImplemented(String), SerializerError(String), IoError(io::Error), NoFieldName, } impl fmt::Display for EncoderError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{:?}", self) } } impl Error for EncoderError { fn description(&self) -> &str { use self::EncoderError::*; match *self { EncodeNotImplemented(ref s) | SerializerError(ref s) => s, IoError(ref e) => e.description(), NoFieldName => "No field name" } } } pub type EncodeResult = Result; impl From for EncoderError { fn from(err: io::Error) -> EncoderError { EncoderError::IoError(err) } } #[derive(Debug)] enum EncoderState { Start, NextKey(String), // NextMapKey, } #[derive(Debug)] pub struct Encoder { keys: Vec, tr: Transaction, state: EncoderState, } const ENCODER_SAM: DWORD = KEY_CREATE_SUB_KEY|KEY_SET_VALUE; impl Encoder { pub fn from_key(key: &RegKey) -> EncodeResult { let tr = try!(Transaction::new()); key.open_subkey_transacted_with_flags("", &tr, ENCODER_SAM) .map(|k| Encoder::new(k, tr)) .map_err(EncoderError::IoError) } fn new(key: RegKey, tr: Transaction) -> Encoder { let mut keys = Vec::with_capacity(5); keys.push(key); Encoder{ keys: keys, tr: tr, state: Start, } } pub fn commit(&mut self) -> EncodeResult<()> { self.tr.commit().map_err(EncoderError::IoError) } } winreg-0.6.0/src/encoder/serialization_serde.rs000064400000000000000000000230031337336373500200240ustar0000000000000000// Copyright 2017, Igor Shaula // Licensed under the MIT License . This file // may not be copied, modified, or distributed // except according to those terms. use std::fmt; use std::mem; use super::{Encoder, EncoderError, EncodeResult, ENCODER_SAM}; use super::EncoderState::*; use serde::ser::*; impl Error for EncoderError { fn custom(msg: T) -> Self { EncoderError::SerializerError(format!("{}", msg)) } } impl<'a> Serializer for &'a mut Encoder { type Ok = (); type Error = EncoderError; type SerializeSeq = SeqEncoder; type SerializeTuple = TupleEncoder; type SerializeTupleStruct = TupleStructEncoder; type SerializeTupleVariant = TupleVariantEncoder; type SerializeMap = MapEncoder<'a>; type SerializeStruct = StructEncoder<'a>; type SerializeStructVariant = StructVariantEncoder; fn serialize_bool(self, value: bool) -> EncodeResult { self.serialize_u32(value as u32) } fn serialize_i8(self, value: i8) -> EncodeResult { self.serialize_i64(value as i64) } fn serialize_i16(self, value: i16) -> EncodeResult { self.serialize_i64(value as i64) } fn serialize_i32(self, value: i32) -> EncodeResult { self.serialize_i64(value as i64) } fn serialize_i64(self, value: i64) -> EncodeResult { let s = value.to_string(); emit_value!(self, s) } fn serialize_u8(self, value: u8) -> EncodeResult { self.serialize_u32(value as u32) } fn serialize_u16(self, value: u16) -> EncodeResult { self.serialize_u32(value as u32) } fn serialize_u32(self, value: u32) -> EncodeResult { emit_value!(self, value) } fn serialize_u64(self, value: u64) -> EncodeResult { emit_value!(self, value) } fn serialize_f32(self, value: f32) -> EncodeResult { let s = value.to_string(); emit_value!(self, s) } fn serialize_f64(self, value: f64) -> EncodeResult { let s = value.to_string(); emit_value!(self, s) } fn serialize_char(self, _value: char) -> EncodeResult { no_impl!("serialize_char") } fn serialize_str(self, value: &str) -> EncodeResult { emit_value!(self, value) } fn serialize_bytes(self, _value: &[u8]) -> EncodeResult { no_impl!("serialize_bytes") } fn serialize_none(self) -> EncodeResult { no_impl!("serialize_none") } fn serialize_some(self, _value: &T) -> EncodeResult { no_impl!("serialize_some") } fn serialize_unit(self) -> EncodeResult { no_impl!("serialize_unit") } fn serialize_unit_struct(self, _name: &'static str) -> EncodeResult { no_impl!("serialize_unit_struct") } fn serialize_unit_variant(self, _name: &'static str, _variant_index: u32, _variant: &'static str) -> EncodeResult { no_impl!("serialize_unit_variant") } fn serialize_newtype_struct(self, _name: &'static str, _value: &T) -> EncodeResult { no_impl!("serialize_newtype_struct") } fn serialize_newtype_variant(self, _name: &'static str, _variant_index: u32, _variant: &'static str, _value: &T) -> EncodeResult { no_impl!("serialize_newtype_variant") } fn serialize_seq(self, _len: Option) -> EncodeResult { no_impl!("serialize_seq") } fn serialize_tuple(self, _len: usize) -> EncodeResult { no_impl!("serialize_tuple") } fn serialize_tuple_struct(self, _name: &'static str, _len: usize) -> EncodeResult { no_impl!("serialize_tuple_struct") } fn serialize_tuple_variant(self, _name: &'static str, _variant_index: u32, _variant: &'static str, _len: usize) -> EncodeResult { no_impl!("serialize_tuple_variant") } fn serialize_map(self, _len: Option) -> EncodeResult { Ok(MapEncoder { _enc: self }) } fn serialize_struct(self, _name: &'static str, _len: usize) -> EncodeResult { match mem::replace(&mut self.state, Start) { Start => { // root structure Ok(StructEncoder { enc: self, is_root: true }) } NextKey(ref s) => { // nested structure match self.keys[self.keys.len() - 1] .create_subkey_transacted_with_flags(&s, &self.tr, ENCODER_SAM) { Ok((subkey, _disp)) => { self.keys.push(subkey); Ok(StructEncoder { enc: self, is_root: true }) } Err(err) => Err(EncoderError::IoError(err)), } } } } fn serialize_struct_variant(self, _name: &'static str, _variant_index: u32, _variant: &'static str, _len: usize) -> EncodeResult { no_impl!("serialize_struct_variant") } } pub struct SeqEncoder {} impl SerializeSeq for SeqEncoder { type Ok = (); type Error = EncoderError; fn serialize_element(&mut self, _value: &T) -> EncodeResult { no_impl!("SerializeSeq::serialize_element") } fn end(self) -> EncodeResult { no_impl!("SerializeSeq::end") } } pub struct TupleEncoder {} impl SerializeTuple for TupleEncoder { type Ok = (); type Error = EncoderError; fn serialize_element(&mut self, _value: &T) -> EncodeResult { no_impl!("SerializeTuple::serialize_element") } fn end(self) -> EncodeResult { no_impl!("SerializeTuple::end") } } pub struct TupleStructEncoder {} impl SerializeTupleStruct for TupleStructEncoder { type Ok = (); type Error = EncoderError; fn serialize_field(&mut self, _value: &T) -> EncodeResult { no_impl!("SerializeTupleStruct::serialize_field") } fn end(self) -> EncodeResult { no_impl!("SerializeTupleStruct::end") } } pub struct TupleVariantEncoder {} impl SerializeTupleVariant for TupleVariantEncoder { type Ok = (); type Error = EncoderError; fn serialize_field(&mut self, _value: &T) -> EncodeResult { no_impl!("SerializeTupleVariant::serialize_field") } fn end(self) -> EncodeResult { no_impl!("SerializeTupleVariant::end") } } pub struct MapEncoder<'a> { _enc: &'a mut Encoder, } impl<'a> SerializeMap for MapEncoder<'a> { type Ok = (); type Error = EncoderError; fn serialize_key(&mut self, _key: &T) -> EncodeResult { no_impl!("SerializeMap::serialize_key") } fn serialize_value(&mut self, _value: &T) -> EncodeResult { no_impl!("SerializeMap::serialize_value") } fn end(self) -> EncodeResult { no_impl!("SerializeMap::end") } } pub struct StructEncoder<'a> { enc: &'a mut Encoder, is_root: bool } impl<'a> SerializeStruct for StructEncoder<'a> { type Ok = (); type Error = EncoderError; fn serialize_field(&mut self, key: &'static str, value: &T) -> EncodeResult { self.enc.state = NextKey(String::from(key)); value.serialize(&mut *self.enc) } fn end(self) -> EncodeResult { if self.is_root { self.enc.keys.pop(); } Ok(()) } } pub struct StructVariantEncoder {} impl SerializeStructVariant for StructVariantEncoder { type Ok = (); type Error = EncoderError; fn serialize_field(&mut self, _key: &'static str, _value: &T) -> EncodeResult { no_impl!("SerializeStructVariant::serialize_field") } fn end(self) -> EncodeResult { no_impl!("SerializeStructVariant::end") } } winreg-0.6.0/src/enums.rs000064400000000000000000000035161337423317300134750ustar0000000000000000// Copyright 2015, Igor Shaula // Licensed under the MIT License . This file // may not be copied, modified, or distributed // except according to those terms. //! `use winreg::enums::*;` to import all needed enumerations and constants use super::winapi; pub use winapi::um::winreg::{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}; pub use winapi::um::winnt::{KEY_QUERY_VALUE, KEY_SET_VALUE, KEY_CREATE_SUB_KEY, KEY_ENUMERATE_SUB_KEYS, KEY_NOTIFY, KEY_CREATE_LINK, KEY_WOW64_32KEY, KEY_WOW64_64KEY, KEY_WOW64_RES, KEY_READ, KEY_WRITE, KEY_EXECUTE, KEY_ALL_ACCESS}; macro_rules! winapi_enum{ ($t:ident, $doc:expr => [$($v:ident),*]) => ( #[doc=$doc] #[allow(non_camel_case_types)] #[derive(Debug,Clone,PartialEq)] pub enum $t { $( $v = winapi::um::winnt::$v as isize ),* } ) } winapi_enum!(RegType, "Enumeration of possible registry value types" => [ REG_NONE, REG_SZ, REG_EXPAND_SZ, REG_BINARY, REG_DWORD, REG_DWORD_BIG_ENDIAN, REG_LINK, REG_MULTI_SZ, REG_RESOURCE_LIST, REG_FULL_RESOURCE_DESCRIPTOR, REG_RESOURCE_REQUIREMENTS_LIST, REG_QWORD ]); pub use self::RegType::*; winapi_enum!(RegDisposition, "Enumeration of possible disposition values" => [ REG_CREATED_NEW_KEY, REG_OPENED_EXISTING_KEY ]); pub use self::RegDisposition::*; winreg-0.6.0/src/lib.rs000064400000000000000000001154371337534701300131220ustar0000000000000000// 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.6" //!``` //! //!```no_run //!extern crate winreg; //!use std::path::Path; //!use std::io; //!use winreg::RegKey; //!use winreg::enums::*; //! //!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); //! //! 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("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_attr(feature="clippy", feature(plugin))] #![cfg_attr(feature="clippy", plugin(clippy))] #![cfg_attr(feature="clippy", warn(option_unwrap_used))] #![cfg_attr(feature="clippy", warn(result_unwrap_used))] extern crate winapi; #[cfg(feature = "serialization-serde")] extern crate serde; use std::ptr; use std::slice; use std::fmt; use std::default::Default; use std::ffi::OsStr; use std::os::windows::ffi::OsStrExt; use std::mem::transmute; use std::io; use winapi::shared::winerror; pub use winapi::shared::minwindef::HKEY; use winapi::shared::minwindef::{DWORD, BYTE, LPBYTE}; use winapi::um::winnt::{self, WCHAR}; use winapi::um::winreg as winapi_reg; use enums::*; use types::{FromRegValue, ToRegValue}; #[cfg(feature = "transactions")] use transaction::Transaction; macro_rules! werr { ($e:expr) => ( Err(io::Error::from_raw_os_error($e as i32)) ) } pub mod enums; pub mod types; #[cfg(feature = "transactions")] pub mod transaction; #[cfg(feature = "serialization-serde")] mod encoder; #[cfg(feature = "serialization-serde")] mod decoder; /// 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 LastWriteTime: winapi::PFILETIME, } /// 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::Debug 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, "RegValue({:?}: {})", self.vtype, f_val) } } /// 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 fn predef(hkey: HKEY) -> RegKey { RegKey{ hkey: hkey } } /// 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 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, ptr::null_mut(), // lpftLastWriteTime: winapi::PFILETIME, ) 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 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 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<()> { let c_path = to_utf16(path); match unsafe { winapi_reg::RegDeleteKeyW( self.hkey, c_path.as_ptr(), //This parameter cannot be NULL. ) as DWORD } { 0 => Ok(()), err => werr!(err) } } /// Part of `transactions` feature. #[cfg(feature = "transactions")] pub fn delete_subkey_transacted>(&self, path: P, t: &Transaction) -> io::Result<()> { let c_path = to_utf16(path); match unsafe { winapi_reg::RegDeleteKeyTransactedW( self.hkey, c_path.as_ptr(), //The value of this parameter cannot be NULL. 0, 0, t.handle, ptr::null_mut(), ) as DWORD } { 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(){ path_ptr = ptr::null(); }else{ c_path = to_utf16(path); path_ptr = 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 = try!( encoder::Encoder::from_key(self) ); try!(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 = try!( 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; 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; 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 } } } /// 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 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() } } #[cfg(all(test, feature = "serialization-serde"))] #[macro_use] extern crate serde_derive; #[cfg(test)] #[cfg_attr(feature="clippy", allow(option_unwrap_used))] #[cfg_attr(feature="clippy", allow(result_unwrap_used))] mod test { extern crate rand; use super::*; use std::collections::HashMap; use self::rand::Rng; use std::ffi::{OsStr,OsString}; #[test] fn test_raw_handle() { let hklm = RegKey::predef(HKEY_LOCAL_MACHINE); let handle = hklm.raw_handle(); assert_eq!(HKEY_LOCAL_MACHINE, handle); } #[test] fn test_open_subkey_with_flags_query_info() { let hklm = RegKey::predef(HKEY_LOCAL_MACHINE); let win = hklm.open_subkey_with_flags("Software\\Microsoft\\Windows", KEY_READ).unwrap(); assert!(win.query_info().is_ok()); assert!(win.open_subkey_with_flags("CurrentVersion\\", KEY_READ).is_ok()); assert!(hklm.open_subkey_with_flags("i\\just\\hope\\nobody\\created\\that\\key", KEY_READ).is_err()); } #[test] fn test_create_subkey_disposition() { let hkcu = RegKey::predef(HKEY_CURRENT_USER); let path = "Software\\WinRegRsTestCreateSubkey"; let (_subkey, disp) = hkcu.create_subkey(path).unwrap(); assert_eq!(disp, REG_CREATED_NEW_KEY); let (_subkey2, disp2) = hkcu.create_subkey(path).unwrap(); assert_eq!(disp2, REG_OPENED_EXISTING_KEY); hkcu.delete_subkey_all(&path).unwrap(); } macro_rules! with_key { ($k:ident, $path:expr => $b:block) => {{ let mut path = "Software\\WinRegRsTest".to_owned(); path.push_str($path); let ($k, _disp) = RegKey::predef(HKEY_CURRENT_USER) .create_subkey(&path).unwrap(); $b RegKey::predef(HKEY_CURRENT_USER) .delete_subkey_all(path).unwrap(); }} } #[test] fn test_delete_subkey() { let path = "Software\\WinRegRsTestDeleteSubkey"; RegKey::predef(HKEY_CURRENT_USER).create_subkey(path).unwrap(); assert!(RegKey::predef(HKEY_CURRENT_USER) .delete_subkey(path).is_ok()); } #[test] fn test_copy_tree() { with_key!(key, "CopyTree" => { let (sub_tree, _sub_tree_disp) = key.create_subkey("Src\\Sub\\Tree").unwrap(); for v in &["one", "two", "three"] { sub_tree.set_value(v, v).unwrap(); } let (dst, _dst_disp) = key.create_subkey("Dst").unwrap(); assert!(key.copy_tree("Src", &dst).is_ok()); }); } #[test] fn test_long_value() { with_key!(key, "LongValue" => { let name = "RustLongVal"; let val1 = RegValue { vtype: REG_BINARY, bytes: (0..6000).map(|_| rand::random::()).collect() }; key.set_raw_value(name, &val1).unwrap(); let val2 = key.get_raw_value(name).unwrap(); assert_eq!(val1, val2); }); } #[test] fn test_string_value() { with_key!(key, "StringValue" => { let name = "RustStringVal"; let val1 = "Test123 \n$%^&|+-*/\\()".to_owned(); key.set_value(name, &val1).unwrap(); let val2: String = key.get_value(name).unwrap(); assert_eq!(val1, val2); }); } #[test] fn test_long_string_value() { with_key!(key, "LongStringValue" => { let name = "RustLongStringVal"; let val1 : String = rand::thread_rng().gen_ascii_chars().take(7000).collect(); key.set_value(name, &val1).unwrap(); let val2: String = key.get_value(name).unwrap(); assert_eq!(val1, val2); }); } #[test] fn test_os_string_value() { with_key!(key, "OsStringValue" => { let name = "RustOsStringVal"; let val1 = OsStr::new("Test123 \n$%^&|+-*/\\()\u{0}"); key.set_value(name, &val1).unwrap(); let val2: OsString = key.get_value(name).unwrap(); assert_eq!(val1, val2); }); } #[test] fn test_long_os_string_value() { with_key!(key, "LongOsStringValue" => { let name = "RustLongOsStringVal"; let mut val1 = rand::thread_rng().gen_ascii_chars().take(7000).collect::(); val1.push('\u{0}'); let val1 = OsStr::new(&val1); key.set_value(name, &val1).unwrap(); let val2: OsString = key.get_value(name).unwrap(); assert_eq!(val1, val2); }); } #[test] fn test_u32_value() { with_key!(key, "U32Value" => { let name = "RustU32Val"; let val1 = 1234567890u32; key.set_value(name, &val1).unwrap(); let val2: u32 = key.get_value(name).unwrap(); assert_eq!(val1, val2); }); } #[test] fn test_u64_value() { with_key!(key, "U64Value" => { let name = "RustU64Val"; let val1 = 1234567891011121314u64; key.set_value(name, &val1).unwrap(); let val2: u64 = key.get_value(name).unwrap(); assert_eq!(val1, val2); }); } #[test] fn test_delete_value() { with_key!(key, "DeleteValue" => { let name = "WinregRsTestVal"; key.set_value(name, &"Qwerty123").unwrap(); assert!(key.delete_value(name).is_ok()); }); } #[test] fn test_enum_keys() { with_key!(key, "EnumKeys" => { let mut keys1 = vec!("qwerty", "asdf", "1", "2", "3", "5", "8", "йцукен"); keys1.sort(); for i in &keys1 { key.create_subkey(i).unwrap(); } let keys2: Vec<_> = key.enum_keys().map(|x| x.unwrap()).collect(); assert_eq!(keys1, keys2); }); } #[test] fn test_enum_values() { with_key!(key, "EnumValues" => { let mut vals1 = vec!("qwerty", "asdf", "1", "2", "3", "5", "8", "йцукен"); vals1.sort(); for i in &vals1 { key.set_value(i,i).unwrap(); } let mut vals2: Vec = Vec::with_capacity(vals1.len()); let mut vals3: Vec = Vec::with_capacity(vals1.len()); for (name, val) in key.enum_values() .map(|x| x.unwrap()) { vals2.push(name); vals3.push(String::from_reg_value(&val).unwrap()); } assert_eq!(vals1, vals2); assert_eq!(vals1, vals3); }); } #[test] fn test_enum_long_values() { with_key!(key, "EnumLongValues" => { let mut vals = HashMap::with_capacity(3); for i in &[5500, 9500, 15000] { let name: String = format!("val{}", i); let val = RegValue { vtype: REG_BINARY, bytes: (0..*i).map(|_| rand::random::()).collect() }; vals.insert(name, val); } for (name, val) in key.enum_values() .map(|x| x.unwrap()) { assert_eq!(val.bytes, vals[&name].bytes); } }); } #[cfg(feature = "serialization-serde")] #[test] fn test_serialization() { #[derive(Debug, PartialEq, Serialize, Deserialize)] struct Rectangle{ x: u32, y: u32, w: u32, h: u32, } #[derive(Debug, PartialEq, Serialize, Deserialize)] struct Test { t_bool: bool, t_u8: u8, t_u16: u16, t_u32: u32, t_u64: u64, t_usize: usize, t_struct: Rectangle, t_string: String, t_i8: i8, t_i16: i16, t_i32: i32, t_i64: i64, t_isize: isize, t_f64: f64, t_f32: f32, } let v1 = Test{ t_bool: false, t_u8: 127, t_u16: 32768, t_u32: 123456789, t_u64: 123456789101112, t_usize: 1234567891, t_struct: Rectangle{ x: 55, y: 77, w: 500, h: 300 }, t_string: "Test123 \n$%^&|+-*/\\()".to_owned(), t_i8: -123, t_i16: -2049, t_i32: 20100, t_i64: -12345678910, t_isize: -1234567890, t_f64: -0.01, t_f32: 3.14, }; with_key!(key, "Serialization" => { key.encode(&v1).unwrap(); let v2: Test = key.decode().unwrap(); assert_eq!(v1, v2); }); } } winreg-0.6.0/src/transaction.rs000064400000000000000000000055441337336430100146730ustar0000000000000000// Copyright 2015, Igor Shaula // Licensed under the MIT License . This file // may not be copied, modified, or distributed // except according to those terms. //! Structure for a registry transaction. //! Part of `transactions` feature. //! //!```no_run //!extern crate winreg; //!use std::io; //!use winreg::RegKey; //!use winreg::enums::*; //!use winreg::transaction::Transaction; //! //!fn main() { //! let t = Transaction::new().unwrap(); //! let hkcu = RegKey::predef(HKEY_CURRENT_USER); //! let (key, _disp) = hkcu.create_subkey_transacted("Software\\RustTransaction", &t).unwrap(); //! key.set_value("TestQWORD", &1234567891011121314u64).unwrap(); //! key.set_value("TestDWORD", &1234567890u32).unwrap(); //! //! println!("Commit transaction? [y/N]:"); //! let mut input = String::new(); //! io::stdin().read_line(&mut input).unwrap(); //! input = input.trim_right().to_owned(); //! if input == "y" || input == "Y" { //! t.commit().unwrap(); //! println!("Transaction committed."); //! } //! else { //! // this is optional, if transaction wasn't committed, //! // it will be rolled back on disposal //! t.rollback().unwrap(); //! //! println!("Transaction wasn't committed, it will be rolled back."); //! } //!} //!``` #![cfg(feature = "transactions")] use std::ptr; use std::io; use winapi::um::winnt; use winapi::um::handleapi; use winapi::um::ktmw32; #[derive(Debug)] pub struct Transaction { pub handle: winnt::HANDLE, } impl Transaction { //TODO: add arguments pub fn new() -> io::Result { unsafe { let handle = ktmw32::CreateTransaction( ptr::null_mut(), ptr::null_mut(), 0, 0, 0, 0, ptr::null_mut(), ); if handle == handleapi::INVALID_HANDLE_VALUE { return Err(io::Error::last_os_error()) }; Ok(Transaction{ handle: handle }) } } pub fn commit(&self) -> io::Result<()> { unsafe { match ktmw32::CommitTransaction(self.handle) { 0 => Err(io::Error::last_os_error()), _ => Ok(()) } } } pub fn rollback(&self) -> io::Result<()> { unsafe { match ktmw32::RollbackTransaction(self.handle) { 0 => Err(io::Error::last_os_error()), _ => Ok(()) } } } fn close_(&mut self) -> io::Result<()> { unsafe { match handleapi::CloseHandle(self.handle) { 0 => Err(io::Error::last_os_error()), _ => Ok(()) } } } } impl Drop for Transaction { fn drop(&mut self) { self.close_().unwrap_or(()); } } winreg-0.6.0/src/types.rs000064400000000000000000000100121337334010300134660ustar0000000000000000// Copyright 2015, Igor Shaula // Licensed under the MIT License . This file // may not be copied, modified, or distributed // except according to those terms. //! Traits for loading/saving Registry values use std::slice; use std::io; use std::ffi::{OsStr,OsString}; use std::os::windows::ffi::{OsStrExt,OsStringExt}; use super::winapi::shared::winerror; use super::{RegValue}; use super::enums::*; use super::{to_utf16,v16_to_v8}; /// A trait for types that can be loaded from registry values. /// /// **NOTE:** Uses `from_utf16_lossy` when converting to `String`. /// /// **NOTE:** When converting to `String`, trailing `NULL` characters are trimmed /// and line separating `NULL` characters in `REG_MULTI_SZ` are replaced by `\n`. /// When converting to `OsString`, all `NULL` characters are left as is. pub trait FromRegValue : Sized { fn from_reg_value(val: &RegValue) -> io::Result; } impl FromRegValue for String { fn from_reg_value(val: &RegValue) -> io::Result { match val.vtype { REG_SZ | REG_EXPAND_SZ | REG_MULTI_SZ => { let words = unsafe { slice::from_raw_parts(val.bytes.as_ptr() as *const u16, val.bytes.len() / 2) }; let mut s = String::from_utf16_lossy(words); while s.ends_with('\u{0}') {s.pop();} if val.vtype == REG_MULTI_SZ { return Ok(s.replace("\u{0}", "\n")) } Ok(s) }, _ => werr!(winerror::ERROR_BAD_FILE_TYPE) } } } impl FromRegValue for OsString { fn from_reg_value(val: &RegValue) -> io::Result { match val.vtype { REG_SZ | REG_EXPAND_SZ | REG_MULTI_SZ => { let words = unsafe { slice::from_raw_parts(val.bytes.as_ptr() as *const u16, val.bytes.len() / 2) }; let s = OsString::from_wide(words); Ok(s) }, _ => werr!(winerror::ERROR_BAD_FILE_TYPE) } } } impl FromRegValue for u32 { fn from_reg_value(val: &RegValue) -> io::Result { match val.vtype { REG_DWORD => { Ok(unsafe{ *(val.bytes.as_ptr() as *const u32) }) }, _ => werr!(winerror::ERROR_BAD_FILE_TYPE) } } } impl FromRegValue for u64 { fn from_reg_value(val: &RegValue) -> io::Result { match val.vtype { REG_QWORD => { Ok(unsafe{ *(val.bytes.as_ptr() as *const u64) }) }, _ => werr!(winerror::ERROR_BAD_FILE_TYPE) } } } /// A trait for types that can be written into registry values. /// /// **NOTE:** Adds trailing `NULL` character to `str` and `String` values /// but **not** to `OsStr` values. pub trait ToRegValue { fn to_reg_value(&self) -> RegValue; } impl ToRegValue for String { fn to_reg_value(&self) -> RegValue { RegValue{ bytes: v16_to_v8(&to_utf16(self)), vtype: REG_SZ } } } impl<'a> ToRegValue for &'a str { fn to_reg_value(&self) -> RegValue { RegValue{ bytes: v16_to_v8(&to_utf16(self)), vtype: REG_SZ } } } impl<'a> ToRegValue for &'a OsStr { fn to_reg_value(&self) -> RegValue { RegValue{ bytes: v16_to_v8(&(self.encode_wide().collect::>())), vtype: REG_SZ } } } impl ToRegValue for u32 { fn to_reg_value(&self) -> RegValue { let bytes: Vec = unsafe { slice::from_raw_parts((self as *const u32) as *const u8, 4).to_vec() }; RegValue{ bytes: bytes, vtype: REG_DWORD } } } impl ToRegValue for u64 { fn to_reg_value(&self) -> RegValue { let bytes: Vec = unsafe { slice::from_raw_parts((self as *const u64) as *const u8, 8).to_vec() }; RegValue{ bytes: bytes, vtype: REG_QWORD } } } winreg-0.6.0/.cargo_vcs_info.json0000644000000001120000000000000123630ustar00{ "git": { "sha1": "ae9dc29381916925acd9d3f6756174e71d13fa72" } }