1use std::ffi::OsStr;
2use std::path::PathBuf;
3use windows::core::HSTRING;
4use windows::Win32::{
5 Foundation::ERROR_FILE_NOT_FOUND,
6 Storage::FileSystem::GetFullPathNameW,
7 System::Com::{CoCreateInstance, CoInitializeEx, CLSCTX_ALL, COINIT_APARTMENTTHREADED},
8 UI::Shell::{
9 FileOperation, IFileOperation, IShellItem, SHCreateItemFromParsingName, FOF_NO_UI,
10 },
11};
12
13pub fn resolve_path(path: &OsStr) -> PathBuf {
14 #[cfg(not(windows))]
17 {
18 return PathBuf::from(path).canonicalize().unwrap();
19 }
20
21 #[cfg(windows)]
22 unsafe {
23 let size = GetFullPathNameW::<&HSTRING>(&HSTRING::from(path.to_str().unwrap()), None, None);
24 let mut buffer = vec![0u16; size as usize];
25 GetFullPathNameW::<&HSTRING>(
26 &HSTRING::from(path.to_str().unwrap()),
27 Some(buffer.as_mut_slice()),
28 None,
29 );
30
31 let expanded_path = String::from_utf16_lossy(&buffer);
32 PathBuf::from(expanded_path.trim_end_matches('\u{0}'))
34 }
35}
36
37pub fn delete_path(path: &PathBuf) -> windows::core::Result<()> {
38 #[cfg(not(windows))]
40 {
41 eprintln!("This program is only intended for Windows.");
42 std::process::exit(1);
43 }
44 unsafe {
50 CoInitializeEx(None, COINIT_APARTMENTTHREADED)?;
51 }
52
53 if !path.try_exists().unwrap_or(false) {
54 return Err(ERROR_FILE_NOT_FOUND.into());
55 }
56
57 let string_path = HSTRING::from(path.to_str().unwrap());
59
60 unsafe {
62 let shell_item =
63 SHCreateItemFromParsingName::<&HSTRING, Option<_>, IShellItem>(&string_path, None)?;
64
65 let file_operation =
67 CoCreateInstance::<Option<_>, IFileOperation>(&FileOperation, None, CLSCTX_ALL)?;
68
69 file_operation.SetOperationFlags(FOF_NO_UI)?;
72 file_operation.DeleteItem(&shell_item, None)?;
73 file_operation.PerformOperations()?;
74 }
75
76 Ok(())
77}