use std::env;
use std::ffi::OsString;
use std::os::windows::ffi::OsStringExt;
use std::path::PathBuf;
use windows::api;
use error::{ DirsError, Result };
pub enum KnownFolder {
RoamingAppData,
LocalAppData,
UserProgramFiles,
Temp,
}
impl Into<api::GUID> for KnownFolder {
fn into(self) -> api::GUID {
use self::KnownFolder::*;
match self {
RoamingAppData => api::GUID {
Data1: 1052149211,
Data2: 26105,
Data3: 19702,
Data4: [160, 58, 227, 239, 101, 114, 159, 61],
},
LocalAppData => api::GUID {
Data1: 4055050117,
Data2: 28602,
Data3: 20431,
Data4: [157, 85, 123, 142, 127, 21, 112, 145],
},
UserProgramFiles => api::GUID {
Data1: 1557638882,
Data2: 8729,
Data3: 19047,
Data4: [184, 93, 108, 156, 225, 86, 96, 203],
},
Temp => api::GUID {
Data1: 0,
Data2: 0,
Data3: 0,
Data4: [0, 0, 0, 0, 0, 0, 0, 0],
},
}
}
}
pub fn get_known_folder_path(folder: KnownFolder) -> Result<PathBuf> {
match folder {
KnownFolder::Temp => Ok(env::temp_dir()),
other => unsafe {
let rfid: api::KNOWNFOLDERID = Into::into(other);
let mut result = 0 as api::PWSTR;
let hresult = api::shlobj::SHGetKnownFolderPath(
&rfid as api::REFKNOWNFOLDERID,
0u32,
0 as api::HANDLE,
&mut result
);
if hresult != api::winerror::S_OK {
return Err(DirsError::PlatformError(
format!("SHGetKnownFolderPath returned 0x{:x}", hresult)
))
}
let mut path = Vec::with_capacity(130); {
let mut current = result;
while *current != 0 {
path.push(*current);
current = current.offset(1);
}
};
let path = OsString::from_wide(path.as_slice());
let path: PathBuf = From::from(path);
api::combaseapi::CoTaskMemFree(
result as api::LPVOID
);
Ok(path)
},
}
}