#![allow(non_camel_case_types, non_snake_case)]
use super::convert_path;
use crate::OpenError;
use normpath::PathExt;
use std::path::Path;
use std::{io, ptr, thread};
use windows_sys::core::HRESULT;
use windows_sys::Win32::System::Com::{CoInitializeEx, CoUninitialize, COINIT_MULTITHREADED};
use windows_sys::Win32::UI::Shell::{ILCreateFromPathW, ILFree, SHOpenFolderAndSelectItems};
pub(crate) fn reveal(path: &Path) -> Result<(), OpenError> {
let path = path.to_owned();
thread::Builder::new()
.spawn(move || reveal_in_thread(&path).map_err(OpenError::Io))
.map_err(OpenError::Io)?
.join()
.expect("COM worker thread should not panic")
}
fn reveal_in_thread(path: &Path) -> io::Result<()> {
unsafe {
to_io_result(CoInitializeEx(ptr::null_mut(), COINIT_MULTITHREADED as u32))?;
}
let item_id_list = {
let path = convert_path(path.normalize()?.as_os_str())?;
let result = unsafe { ILCreateFromPathW(path.as_ptr()) };
if result.is_null() {
return Err(io::Error::last_os_error());
} else {
result
}
};
unsafe {
let result = to_io_result(SHOpenFolderAndSelectItems(item_id_list, 0, ptr::null(), 0));
ILFree(item_id_list);
CoUninitialize();
result
}
}
fn to_io_result(hresult: HRESULT) -> io::Result<()> {
if hresult >= 0 {
Ok(())
} else {
Err(io::Error::from_raw_os_error(hresult & 0xFFFF))
}
}