use std::{marker::PhantomData, mem, ops::Deref, os::raw::c_void};
use derive_more::From;
use windows::{
Win32::{
System::Com::{CLSCTX_ALL, CoCreateInstance, CoTaskMemFree},
UI::Shell::{Common::ITEMIDLIST, IPersistIDList, IShellItem, SHGetIDListFromObject},
},
core::{IUnknown, Interface, Param, Result},
};
use super::item::ShellItem;
#[derive(Debug, Clone, From)]
pub struct ChildID(pub *mut ITEMIDLIST);
impl From<RelativeIDList> for ChildID {
fn from(value: RelativeIDList) -> Self {
let id = Self(value.0);
mem::forget(value);
id
}
}
impl ChildID {
pub fn to_ref(&self) -> ChildIDRef<'_> {
self.into()
}
}
impl Drop for ChildID {
fn drop(&mut self) {
unsafe { CoTaskMemFree(Some(self.0.cast())) }
}
}
#[derive(Debug, Clone, Copy)]
pub struct ChildIDRef<'a>(pub *const ITEMIDLIST, PhantomData<&'a ()>);
impl<'a> ChildIDRef<'a> {
pub unsafe fn from_raw(ptr: *const ITEMIDLIST) -> Self {
Self(ptr, PhantomData)
}
}
impl<'a> From<&'a ChildID> for ChildIDRef<'a> {
fn from(id: &'a ChildID) -> Self {
Self(id.0, PhantomData)
}
}
impl<'a> Deref for ChildIDRef<'a> {
type Target = ChildID;
fn deref(&self) -> &Self::Target {
unsafe { mem::transmute(self) }
}
}
#[derive(Debug, Clone, From)]
pub struct RelativeIDList(pub *mut ITEMIDLIST);
impl Drop for RelativeIDList {
fn drop(&mut self) {
unsafe { CoTaskMemFree(Some(self.0.cast())) }
}
}
#[derive(Debug, Clone, Copy)]
pub struct RelativeIDListRef<'a>(pub *const ITEMIDLIST, PhantomData<&'a ()>);
impl<'a> RelativeIDListRef<'a> {
pub unsafe fn from_raw(ptr: *const ITEMIDLIST) -> Self {
Self(ptr, PhantomData)
}
}
impl<'a> From<&'a RelativeIDList> for RelativeIDListRef<'a> {
fn from(id: &'a RelativeIDList) -> Self {
Self(id.0, PhantomData)
}
}
impl<'a> Deref for RelativeIDListRef<'a> {
type Target = RelativeIDList;
fn deref(&self) -> &Self::Target {
unsafe { mem::transmute(self) }
}
}
impl RelativeIDList {
pub fn into_child(self) -> ChildID {
self.into()
}
pub fn to_child_ref(&self) -> ChildIDRef<'_> {
ChildIDRef(self.0, PhantomData)
}
}
#[derive(Debug, Clone, From)]
pub struct AbsoluteIDList(pub *mut ITEMIDLIST);
impl AbsoluteIDList {
pub fn from_raw_void_ref<'a>(pidl: &'a *mut c_void) -> &'a Self {
unsafe { mem::transmute(pidl) }
}
pub fn from_object(unk: impl Param<IUnknown>) -> Result<Self> {
unsafe { SHGetIDListFromObject(unk) }.map(AbsoluteIDList)
}
}
impl Drop for AbsoluteIDList {
fn drop(&mut self) {
unsafe { CoTaskMemFree(Some(self.0.cast())) }
}
}
#[derive(Debug, Clone, Copy)]
pub struct AbsoluteIDListRef<'a>(pub *const ITEMIDLIST, PhantomData<&'a ()>);
impl<'a> AbsoluteIDListRef<'a> {
pub unsafe fn from_raw(ptr: *const ITEMIDLIST) -> Self {
Self(ptr, PhantomData)
}
}
impl<'a> From<&'a AbsoluteIDList> for AbsoluteIDListRef<'a> {
fn from(id: &'a AbsoluteIDList) -> Self {
Self(id.0, PhantomData)
}
}
impl<'a> Deref for AbsoluteIDListRef<'a> {
type Target = AbsoluteIDList;
fn deref(&self) -> &Self::Target {
unsafe { mem::transmute(self) }
}
}
pub trait PersistIDList {
fn new() -> Result<IPersistIDList>;
fn get_id_list(&self) -> Result<AbsoluteIDList>;
fn to_shell_item(&self) -> Result<IShellItem>;
}
impl PersistIDList for IPersistIDList {
fn new() -> Result<IPersistIDList> {
unsafe { CoCreateInstance(&IPersistIDList::IID, None, CLSCTX_ALL) }
}
fn get_id_list(&self) -> Result<AbsoluteIDList> {
unsafe { self.GetIDList() }.map(AbsoluteIDList)
}
fn to_shell_item(&self) -> Result<IShellItem> {
let id_list = self.get_id_list()?;
let item = IShellItem::from_id_list(&id_list)?;
Ok(item)
}
}