extern crate winapi;
use self::winapi::shared::guiddef::GUID;
use self::winapi::um::combaseapi::CoTaskMemFree;
use self::winapi::um::shlobj::SHGetKnownFolderPath;
use self::winapi::um::winnt::PWSTR;
use crate::common::*;
use crate::AppDataType::*;
use std::ffi::OsString;
use std::os::windows::ffi::OsStringExt;
use std::path::PathBuf;
use std::ptr;
use std::slice;
pub const USE_AUTHOR: bool = true;
pub fn get_app_dir(t: AppDataType) -> Result<PathBuf, AppDirsError> {
let folder_id = match t {
UserConfig => &FOLDERID_RoamingAppData,
SharedConfig | SharedData => &FOLDERID_ProgramData,
UserCache | UserData => &FOLDERID_LocalAppData,
};
get_folder_path(folder_id).map(|os_str| os_str.into())
}
#[allow(non_upper_case_globals)]
static FOLDERID_RoamingAppData: GUID = GUID {
Data1: 0x3EB685DB,
Data2: 0x65F9,
Data3: 0x4CF6,
Data4: [0xA0, 0x3A, 0xE3, 0xEF, 0x65, 0x72, 0x9F, 0x3D],
};
#[allow(non_upper_case_globals)]
static FOLDERID_LocalAppData: GUID = GUID {
Data1: 0xF1B32785,
Data2: 0x6FBA,
Data3: 0x4FCF,
Data4: [0x9D, 0x55, 0x7B, 0x8E, 0x7F, 0x15, 0x70, 0x91],
};
#[allow(non_upper_case_globals)]
static FOLDERID_ProgramData: GUID = GUID {
Data1: 0x62AB5D82,
Data2: 0xFDC1,
Data3: 0x4DC3,
Data4: [0xA9, 0xDD, 0x07, 0x0D, 0x1D, 0x49, 0x5D, 0x97],
};
struct SafePwstr(PWSTR);
impl Drop for SafePwstr {
fn drop(&mut self) {
unsafe { CoTaskMemFree(self.0 as *mut _) }
}
}
fn get_folder_path(folder_id: &GUID) -> Result<OsString, AppDirsError> {
unsafe {
let mut raw_path: PWSTR = ptr::null_mut();
let result = SHGetKnownFolderPath(folder_id, 0, ptr::null_mut(), &mut raw_path);
if result < 0 {
return Err(AppDirsError::NotSupported);
}
let _cleanup = SafePwstr(raw_path);
let mut length = 0;
for i in 0.. {
if *raw_path.offset(i) == 0 {
length = i as usize;
break;
}
}
let wpath: &[u16] = slice::from_raw_parts(raw_path, length);
let path: OsString = OsStringExt::from_wide(wpath);
Ok(path)
}
}