1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
//! This crate provides access to Windows APIs for querying the location of standard
//! [standard Windows folders](https://msdn.microsoft.com/en-us/library/windows/desktop/bb776911.aspx)
//! on the current system.
//!
//! # Example
//!
//! ```
//! extern crate winfolder;
//!
//! use winfolder::Folder;
//!
//! # fn main() {
//! # let _ =
//! Folder::ProgramFilesX86.path()
//! # ;
//! # }
//! ```
#![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;
/// Construct an `OsString` from a pointer to a wide-character string.
/// This is marked as unsafe because it can only be safely used on a
/// string that is known to come from a trusted API.
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
}
/// Returns the path for a Windows
/// [known folder](https://msdn.microsoft.com/en-us/library/windows/desktop/bb776911.aspx)
/// based on that folder's GUID. Some standard known folder GUIDs can be found in
/// the `winfolder::id` module.
///
/// If the GUID does not represent a standard folder, this function
/// produces `None`.
///
/// This function provides the functionality of the standard Windows
/// [SHGetKnownFolderPath](https://msdn.microsoft.com/en-us/library/windows/desktop/bb762188.aspx)
/// API.
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())
}
/// Represents a standard Windows [known folder](https://msdn.microsoft.com/en-us/library/windows/desktop/bb776911.aspx).
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
pub enum Folder {
/// The [`FOLDERID_LocalAppData`](https://msdn.microsoft.com/en-us/library/windows/desktop/dd378457.aspx#folderid_localappdata)
/// known folder.
LocalAppData,
/// The [`FOLDERID_ProgramData`](https://msdn.microsoft.com/en-us/library/windows/desktop/dd378457.aspx#folderid_programdata)
/// known folder.
ProgramData,
/// The [`FOLDERID_ProgramFiles`](https://msdn.microsoft.com/en-us/library/windows/desktop/dd378457.aspx#folderid_programfiles)
/// known folder.
ProgramFiles,
/// The [`FOLDERID_ProgramFilesX64`](https://msdn.microsoft.com/en-us/library/windows/desktop/dd378457.aspx#folderid_programfilesx64)
/// known folder.
ProgramFilesX64,
/// The [`FOLDERID_ProgramFilesX86`](https://msdn.microsoft.com/en-us/library/windows/desktop/dd378457.aspx#folderid_programfilesx86)
/// known folder.
ProgramFilesX86
}
impl Folder {
/// Returns the Windows GUID associated with this known 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
}
}
/// Returns the path for this known folder on this system.
///
/// This function provides the functionality of the standard Windows
/// [SHGetKnownFolderPath](https://msdn.microsoft.com/en-us/library/windows/desktop/bb762188.aspx)
/// API.
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());
}
}