use std::vec::Vec;
use std::ptr::null_mut;
use std::ptr::null;
use std::ffi::OsString;
use std::ffi::OsStr;
use std::os::windows::ffi::OsStringExt;
use std::os::windows::ffi::OsStrExt;
use winapi::um::winreg::RegOpenKeyExW;
use winapi::shared::minwindef::HKEY;
use winapi::um::winnt::KEY_READ;
use winapi::shared::winerror::ERROR_SUCCESS;
use winapi::shared::winerror::ERROR_FILE_NOT_FOUND;
use winapi::shared::winerror::ERROR_ACCESS_DENIED;
use winapi::um::winreg::RegGetValueW;
use winapi::um::winreg::RegSetValueExW;
use winapi::um::winreg::RRF_RT_ANY;
use winapi::shared::minwindef::DWORD;
use winapi::um::winnt::REG_EXPAND_SZ;
use winapi::um::winreg::HKEY_CURRENT_USER;
use winapi::um::winreg::HKEY_LOCAL_MACHINE;
#[derive(Clone, Copy, Debug)]
pub enum Error
{
NoFound,
AccessDenied,
Other(u32)
}
#[derive(Clone, Copy, Debug)]
pub enum RootKey
{
CurrentUser,
LocalMachine
}
fn root_key_to_hkey(root: RootKey) -> HKEY
{
match root
{
RootKey::CurrentUser => HKEY_CURRENT_USER,
RootKey::LocalMachine => HKEY_LOCAL_MACHINE
}
}
fn handle_error(errcode: DWORD) -> Error
{
match errcode
{
ERROR_FILE_NOT_FOUND => return Error::NoFound,
ERROR_ACCESS_DENIED => return Error::AccessDenied,
v => return Error::Other(v)
};
}
pub fn get_registry_string(root: RootKey, path: &str, name: &str) -> Result<(OsString, DWORD), Error>
{
let mut wpath: Vec<u16> = OsString::from(path).encode_wide().collect();
let mut wname: Vec<u16> = OsString::from(name).encode_wide().collect();
wpath.push(0);
wname.push(0);
unsafe
{
let root_key = root_key_to_hkey(root);
let mut hkey: HKEY = null_mut();
let err = RegOpenKeyExW(root_key, wpath.as_ptr(), 0, KEY_READ, &mut hkey as _);
if err as DWORD != ERROR_SUCCESS
{
println!("err1");
return Err(handle_error(err as DWORD));
}
let mut size: DWORD = 0;
let err = RegGetValueW(hkey, null(), wname.as_ptr(), RRF_RT_ANY, null_mut(), null_mut(), &mut size as _);
if err as DWORD != ERROR_SUCCESS
{
println!("err2");
return Err(handle_error(err as DWORD));
}
let mut buf: Vec<u16> = vec![0; size as usize];
let mut typeasf: DWORD = 0;
let err = RegGetValueW(hkey, null(), wname.as_ptr(), RRF_RT_ANY, &mut typeasf as _, buf.as_mut_ptr() as _, &mut size as _);
if err as DWORD != ERROR_SUCCESS
{
println!("err3");
return Err(handle_error(err as DWORD));
}
let len = buf.iter().take_while(|&&c| c != 0).count();
return Ok((OsString::from_wide(&buf[..len]), typeasf));
}
}
pub fn set_registry_string(root: RootKey, path: &str, name: &str, value: &OsStr, typeasf: DWORD) -> Result<(), Error>
{
let mut wpath: Vec<u16> = OsString::from(path).encode_wide().collect();
let mut wname: Vec<u16> = OsString::from(name).encode_wide().collect();
let mut wvalue: Vec<u16> = value.encode_wide().collect();
wpath.push(0);
wname.push(0);
wvalue.push(0);
unsafe
{
let root_key = root_key_to_hkey(root);
let mut hkey: HKEY = null_mut();
let err = RegOpenKeyExW(root_key, wpath.as_ptr(), 0, KEY_READ, &mut hkey as _);
if err as DWORD != ERROR_SUCCESS
{
return Err(handle_error(err as DWORD));
}
let err = RegSetValueExW(hkey, wname.as_ptr(), 0, typeasf, wvalue.as_ptr() as _, (wvalue.len() * 2) as DWORD);
if err as DWORD != ERROR_SUCCESS
{
return Err(handle_error(err as DWORD));
}
}
return Ok(());
}
const REG_PATH_USER: &'static str = "Environment";
const REG_PATH_SYS: &'static str = "SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment";
const REG_PATH_NAME: &'static str = "Path";
pub fn get_path(user: bool) -> Result<Vec<OsString>, Error>
{
let mut v = Vec::new();
let (data, _) = match user
{
true => get_registry_string(RootKey::CurrentUser, REG_PATH_USER, REG_PATH_NAME)?,
false => get_registry_string(RootKey::LocalMachine, REG_PATH_SYS, REG_PATH_NAME)?,
};
let wdata: Vec<u16> = data.encode_wide().collect();
let mut word = Vec::new();
for c in wdata
{
if c == 0x003b
{
if word.len() > 0
{
v.push(OsString::from_wide(&word));
word.clear();
}
}
else
{
word.push(c);
}
}
return Ok(v);
}
pub fn set_path(user: bool, new_path: Vec<OsString>) -> Result<(), Error>
{
let mut s = OsString::new();
for p in new_path
{
s.push(p);
s.push(";");
}
if user
{
return set_registry_string(RootKey::CurrentUser, REG_PATH_USER, REG_PATH_NAME, &s, REG_EXPAND_SZ);
}
else
{
return set_registry_string(RootKey::LocalMachine, REG_PATH_SYS, REG_PATH_NAME, &s, REG_EXPAND_SZ);
}
}