Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  lib.rs   Sprache: unbekannt

 
// Copyright 2015, Igor Shaula
// Licensed under the MIT License <LICENSE or
// http://opensource.org/licenses/MIT>. 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<String> = 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<u8>,
    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<dyn Error>> {
    /// let handle = RegKey::load_app_key("C:\\myhive.dat", false)?;
    /// # Ok(())
    /// # }
    /// ```
    pub fn load_app_key<N: AsRef<OsStr>>(filename: N, lock: bool) -> io::Result<RegKey> {
        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<dyn Error>> {
    /// let handle = RegKey::load_app_key_with_flags("C:\\myhive.dat", KEY_READ, 0)?;
    /// # Ok(())
    /// # }
    /// ```
    pub fn load_app_key_with_flags<N: AsRef<OsStr>>(
        filename: N,
        perms: winapi_reg::REGSAM,
        options: DWORD,
    ) -> io::Result<RegKey> {
        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<dyn Error>> {
    /// 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<dyn Error>> {
    /// let soft = RegKey::predef(HKEY_CURRENT_USER)
    ///     .open_subkey("Software")?;
    /// # Ok(())
    /// # }
    /// ```
    pub fn open_subkey<P: AsRef<OsStr>>(&self, path: P) -> io::Result<RegKey> {
        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<dyn Error>> {
    /// let hklm = RegKey::predef(HKEY_LOCAL_MACHINE);
    /// hklm.open_subkey_with_flags("SOFTWARE\\Microsoft", KEY_READ)?;
    /// # Ok(())
    /// # }
    /// ```
    pub fn open_subkey_with_flags<P: AsRef<OsStr>>(
        &self,
        path: P,
        perms: winapi_reg::REGSAM,
    ) -> io::Result<RegKey> {
        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<P: AsRef<OsStr>>(
        &self,
        path: P,
        t: &Transaction,
    ) -> io::Result<RegKey> {
        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<P: AsRef<OsStr>>(
        &self,
        path: P,
        t: &Transaction,
        perms: winapi_reg::REGSAM,
    ) -> io::Result<RegKey> {
        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<dyn Error>> {
    /// 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<P: AsRef<OsStr>>(&self, path: P) -> io::Result<(RegKey, RegDisposition)> {
        self.create_subkey_with_flags(path, enums::KEY_ALL_ACCESS)
    }

    pub fn create_subkey_with_flags<P: AsRef<OsStr>>(
        &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<P: AsRef<OsStr>>(
        &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<P: AsRef<OsStr>>(
        &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<dyn Error>> {
    /// 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<P: AsRef<OsStr>>(&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<RegKeyMetadata> {
        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<dyn Error>> {
    /// 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<dyn Error>> {
    /// RegKey::predef(HKEY_CURRENT_USER)
    ///     .delete_subkey(r"Software\MyProduct\History")?;
    /// # Ok(())
    /// # }
    /// ```
    pub fn delete_subkey<P: AsRef<OsStr>>(&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<dyn Error>> {
    /// // 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<P: AsRef<OsStr>>(
        &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<P: AsRef<OsStr>>(
        &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<P: AsRef<OsStr>>(
        &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<dyn Error>> {
    /// RegKey::predef(HKEY_CURRENT_USER)
    ///     .delete_subkey_all("Software\\MyProduct")?;
    /// # Ok(())
    /// # }
    /// ```
    pub fn delete_subkey_all<P: AsRef<OsStr>>(&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<dyn Error>> {
    /// 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<T: FromRegValue, N: AsRef<OsStr>>(&self, name: N) -> io::Result<T> {
        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<dyn Error>> {
    /// 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<N: AsRef<OsStr>>(&self, name: N) -> io::Result<RegValue> {
        let c_name = to_utf16(name);
        let mut buf_len: DWORD = 2048;
        let mut buf_type: DWORD = 0;
        let mut buf: Vec<u8> = 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<dyn Error>> {
    /// 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<T: ToRegValue, N: AsRef<OsStr>>(&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<dyn Error>> {
    /// let hkcu = RegKey::predef(HKEY_CURRENT_USER);
    /// let settings = hkcu.open_subkey("Software\\MyProduct\\Settings")?;
    /// let bytes: Vec<u8> = 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<N: AsRef<OsStr>>(&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<dyn Error>> {
    /// let hkcu = RegKey::predef(HKEY_CURRENT_USER);
    /// let settings = hkcu.open_subkey("Software\\MyProduct\\Settings")?;
    /// settings.delete_value("data")?;
    /// # Ok(())
    /// # }
    /// ```
    pub fn delete_value<N: AsRef<OsStr>>(&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<dyn Error>> {
    /// 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<T: serde::Serialize>(&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<dyn Error>> {
    /// 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<T> {
        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<io::Result<String>> {
        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<io::Result<(String, RegValue)>> {
        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<u8> = 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<String>;

    fn next(&mut self) -> Option<io::Result<String>> {
        match self.key.enum_key(self.index) {
            v @ Some(_) => {
                self.index += 1;
                v
            }
            e @ None => e,
        }
    }

    fn nth(&mut self, n: usize) -> Option<Self::Item> {
        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<io::Result<(String, RegValue)>> {
        match self.key.enum_value(self.index) {
            v @ Some(_) => {
                self.index += 1;
                v
            }
            e @ None => e,
        }
    }

    fn nth(&mut self, n: usize) -> Option<Self::Item> {
        self.index += n as DWORD;
        self.next()
    }
}

fn to_utf16<P: AsRef<OsStr>>(s: P) -> Vec<u16> {
    s.as_ref()
        .encode_wide()
        .chain(Some(0).into_iter())
        .collect()
}

fn v16_to_v8(v: &[u16]) -> Vec<u8> {
    unsafe { slice::from_raw_parts(v.as_ptr() as *const u8, v.len() * 2).to_vec() }
}

[ Dauer der Verarbeitung: 0.42 Sekunden  (vorverarbeitet)  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge