#![cfg(windows)]
extern crate winapi;
extern crate shell32;
extern crate ole32;
#[macro_use]
extern crate guid;
pub mod id;
use id::*;
use std::ptr::null_mut;
use std::mem;
use std::ffi::OsString;
use std::slice;
use std::os::windows::ffi::OsStringExt;
use std::path::{Path, PathBuf};
use winapi::winnt::PWSTR;
use winapi::minwindef::MAX_PATH;
use shell32::SHGetKnownFolderPath;
use ole32::CoTaskMemFree;
unsafe fn os_string_from_trusted_api(mut p: PWSTR) -> OsString {
let mut s: OsString = OsString::with_capacity(MAX_PATH + 1);
while *p != 0 {
s.push(&OsString::from_wide(slice::from_raw_parts(p, 1)));
p = p.offset(1);
}
s
}
pub fn known_path(guid: &guid::GUID) -> Option<PathBuf> {
let string: OsString;
unsafe {
let mut path: PWSTR = null_mut();
if SHGetKnownFolderPath(guid, 0, null_mut(), mem::transmute(&mut path)) != 0 {
return None;
}
string = os_string_from_trusted_api(path);
CoTaskMemFree(mem::transmute(path));
}
Some(Path::new(&string).to_path_buf())
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
pub enum Folder {
LocalAppData,
ProgramData,
ProgramFiles,
ProgramFilesX64,
ProgramFilesX86
}
impl Folder {
pub fn id(self) -> guid::GUID {
match self {
Folder::LocalAppData => LOCAL_APP_DATA,
Folder::ProgramData => PROGRAM_DATA,
Folder::ProgramFiles => PROGRAM_FILES,
Folder::ProgramFilesX64 => PROGRAM_FILES_X64,
Folder::ProgramFilesX86 => PROGRAM_FILES_X86
}
}
pub fn path(self) -> PathBuf {
known_path(&self.id()).expect("Folder::path")
}
}
#[cfg(test)]
mod tests {
use super::{known_path, Folder};
use super::id;
use std::path::Path;
#[test]
fn it_works() {
assert_eq!(known_path(&id::PROGRAM_FILES_X86), Some(Path::new(r"C:\Program Files (x86)").to_path_buf()));
assert_eq!(Folder::ProgramFilesX86.path(), Path::new(r"C:\Program Files (x86)").to_path_buf());
}
}