use core::mem::size_of;
use core::ptr;
use core::slice;
use std::ffi::OsString;
use std::os::windows::ffi::OsStringExt;
use std::path::PathBuf;
use windows_sys::Win32::{
Foundation::{E_FAIL, E_INVALIDARG, S_OK},
Globalization::lstrlenW,
UI::Shell::{SHGetKnownFolderPath, KF_FLAG_DEFAULT},
};
mod ffi;
mod known_folder;
pub use known_folder::KnownFolder;
#[must_use]
#[allow(clippy::match_same_arms)]
#[allow(clippy::cast_possible_wrap)]
pub fn get_known_folder_path(known_folder: KnownFolder) -> Option<PathBuf> {
let mut guard = ffi::Guard::default();
match unsafe {
SHGetKnownFolderPath(
known_folder.to_guid(),
KF_FLAG_DEFAULT as _,
ptr::null_mut(),
guard.as_out_ppszPath(),
)
} {
S_OK => {
let path_ptr = guard.as_pcwstr();
let len = unsafe {
let len = lstrlenW(path_ptr);
usize::try_from(len).ok()?
};
let path = unsafe {
match isize::try_from(len) {
Ok(len) if len < 0 => return None,
Ok(len) if len.checked_mul(size_of::<u16>() as isize).is_some() => {}
Ok(_) | Err(_) => return None,
}
slice::from_raw_parts(path_ptr, len)
};
let os_str = OsString::from_wide(path);
Some(os_str.into())
}
E_FAIL | E_INVALIDARG => None,
_ => None,
}
}