Skip to main content

ib_shell_item/
path.rs

1use std::path::{Path, PathBuf};
2
3use widestring::U16CStr;
4use windows::{Win32::UI::Shell::IShellItem, core::Result};
5
6use crate::{ShellItem, ShellItemDisplayName, id_list::AbsoluteIDList};
7
8/// A file system path or Windows Shell item ID list (PIDL).
9#[derive(Clone)]
10pub enum ShellPath<'a> {
11    Path(PathBuf),
12    // `(*const ITEMIDLIST, PhantomData<&'a ()>)`
13    IdList(&'a AbsoluteIDList),
14}
15
16impl From<PathBuf> for ShellPath<'static> {
17    fn from(value: PathBuf) -> Self {
18        Self::Path(value)
19    }
20}
21
22impl From<&Path> for ShellPath<'static> {
23    fn from(value: &Path) -> Self {
24        Self::Path(value.into())
25    }
26}
27
28impl<'a> ShellPath<'a> {
29    pub fn from_path_or_id_list(path: *const u16, id_list: &'a AbsoluteIDList) -> Option<Self> {
30        match (path.is_null(), id_list.0.is_null()) {
31            (true, true) => None,
32            // Prefer lpFile
33            (false, _) => {
34                let file = unsafe { U16CStr::from_ptr_str(path) };
35
36                Self::Path(file.to_os_string().into()).into()
37            }
38            (true, false) => Self::IdList(id_list).into(),
39        }
40    }
41
42    pub fn to_file_path(&self) -> Result<PathBuf> {
43        Ok(match self {
44            ShellPath::Path(path) => path.clone(),
45            ShellPath::IdList(id_list) => {
46                let item = IShellItem::from_id_list(id_list)?;
47                let name = item.get_display_name(ShellItemDisplayName::FileSystemPath)?;
48                name.to_os_string().into()
49            }
50        })
51    }
52}
53
54impl<'a> std::fmt::Debug for ShellPath<'a> {
55    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
56        match self {
57            Self::Path(arg0) => f.debug_tuple("Path").field(arg0).finish(),
58            Self::IdList(arg0) => {
59                let mut f = f.debug_tuple("IdList");
60                let f = f.field(arg0);
61                if let Ok(path) = self.to_file_path() {
62                    f.field(&path);
63                }
64                f.finish()
65            }
66        }
67    }
68}