diff --git a/opener/Cargo.toml b/opener/Cargo.toml index 2d26d6d..f2dc3c5 100644 --- a/opener/Cargo.toml +++ b/opener/Cargo.toml @@ -15,7 +15,7 @@ maintenance = { status = "passively-maintained" } [features] default = ["dbus-vendored"] -reveal = ["dep:url", "dep:dbus", "winapi/shtypes", "winapi/objbase"] +reveal = ["dep:url", "dep:dbus", "windows-sys/Win32_System_Com"] dbus-vendored = ["dbus/vendored"] [dev-dependencies] @@ -28,7 +28,11 @@ url = { version = "2", optional = true } [target.'cfg(windows)'.dependencies] normpath = "1" -winapi = { version = "0.3", features = ["shellapi", "winerror"] } +windows-sys = { version = "0.52", features = [ + "Win32_Foundation", + "Win32_UI_Shell", + "Win32_UI_WindowsAndMessaging", +] } [package.metadata.docs.rs] all-features = true diff --git a/opener/src/windows.rs b/opener/src/windows.rs index dbdc943..7d50fc1 100644 --- a/opener/src/windows.rs +++ b/opener/src/windows.rs @@ -4,8 +4,8 @@ use std::ffi::OsStr; use std::os::windows::ffi::OsStrExt; use std::path::PathBuf; use std::{io, ptr}; -use winapi::ctypes::c_int; -use winapi::um::shellapi::ShellExecuteW; +use windows_sys::Win32::UI::Shell::ShellExecuteW; +use windows_sys::Win32::UI::WindowsAndMessaging::SW_SHOW; #[cfg(feature = "reveal")] mod reveal; @@ -27,13 +27,11 @@ pub(crate) fn open(path: &OsStr) -> Result<(), OpenError> { } pub(crate) fn open_helper(path: &OsStr) -> Result<(), OpenError> { - const SW_SHOW: c_int = 5; - let path = convert_path(path).map_err(OpenError::Io)?; let operation: Vec = OsStr::new("open\0").encode_wide().collect(); let result = unsafe { ShellExecuteW( - ptr::null_mut(), + 0, operation.as_ptr(), path.as_ptr(), ptr::null(), @@ -41,7 +39,7 @@ pub(crate) fn open_helper(path: &OsStr) -> Result<(), OpenError> { SW_SHOW, ) }; - if result as c_int > 32 { + if result > 32 { Ok(()) } else { Err(OpenError::Io(io::Error::last_os_error())) diff --git a/opener/src/windows/reveal.rs b/opener/src/windows/reveal.rs index bd0958f..4488bb9 100644 --- a/opener/src/windows/reveal.rs +++ b/opener/src/windows/reveal.rs @@ -1,16 +1,12 @@ +#![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 winapi::shared::minwindef::{DWORD, UINT}; -use winapi::shared::ntdef::PCWSTR; -use winapi::shared::winerror::HRESULT; -use winapi::um::combaseapi::{CoInitializeEx, CoUninitialize}; -use winapi::um::objbase::COINIT_MULTITHREADED; -use winapi::um::shtypes::{ - PCIDLIST_ABSOLUTE, PCUITEMID_CHILD_ARRAY, PIDLIST_ABSOLUTE, PIDLIST_RELATIVE, -}; +use windows_sys::core::{HRESULT, PCWSTR}; +use windows_sys::Win32::System::Com::{CoInitializeEx, CoUninitialize, COINIT_MULTITHREADED}; pub(crate) fn reveal(path: &Path) -> Result<(), OpenError> { let path = path.to_owned(); @@ -22,57 +18,70 @@ pub(crate) fn reveal(path: &Path) -> Result<(), OpenError> { } fn reveal_in_thread(path: &Path) -> io::Result<()> { - to_io_result(unsafe { CoInitializeEx(ptr::null_mut(), COINIT_MULTITHREADED) })?; - let item_id_list = ItemIdList::new(path)?; - // Because the cidl argument is zero, SHOpenFolderAndSelectItems opens the singular item - // in our item id list in its containing folder and selects it. - to_io_result(unsafe { SHOpenFolderAndSelectItems(item_id_list.0, 0, ptr::null(), 0) })?; - unsafe { CoUninitialize() }; - Ok(()) -} - -fn to_io_result(hresult: HRESULT) -> io::Result<()> { - if hresult >= 0 { - Ok(()) - } else { - // See the HRESULT_CODE macro in winerror.h - Err(io::Error::from_raw_os_error(hresult & 0xFFFF)) + unsafe { + to_io_result(CoInitializeEx(ptr::null_mut(), COINIT_MULTITHREADED as u32))?; } -} - -struct ItemIdList(PIDLIST_ABSOLUTE); -impl ItemIdList { - fn new(path: &Path) -> io::Result { + let item_id_list = { // The ILCreateFromPathW function expects a canonicalized path. // Unfortunately it does not support NT UNC paths (which std::path::canonicalize returns) // so we use the normpath crate instead. let path = convert_path(path.normalize()?.as_os_str())?; let result = unsafe { ILCreateFromPathW(path.as_ptr()) }; if result.is_null() { - Err(io::Error::last_os_error()) + return Err(io::Error::last_os_error()); } else { - Ok(ItemIdList(result)) + result } + }; + + unsafe { + // Because the cidl argument is zero, SHOpenFolderAndSelectItems opens the singular item + // in our item id list in its containing folder and selects it. + let result = to_io_result(SHOpenFolderAndSelectItems(item_id_list, 0, ptr::null(), 0)); + ILFree(item_id_list); + CoUninitialize(); + + result } } -impl Drop for ItemIdList { - fn drop(&mut self) { - unsafe { ILFree(self.0) } +fn to_io_result(hresult: HRESULT) -> io::Result<()> { + if hresult >= 0 { + Ok(()) + } else { + // See the HRESULT_CODE macro in winerror.h + Err(io::Error::from_raw_os_error(hresult & 0xFFFF)) } } +// +// +// + +#[repr(C)] +#[repr(packed)] +struct ITEMIDLIST { + mkid: SHITEMID, +} + +#[repr(C)] +#[repr(packed)] +struct SHITEMID { + cb: u16, + abID: [u8; 1], +} + #[link(name = "Shell32")] extern "C" { - fn ILCreateFromPathW(pszPath: PCWSTR) -> PIDLIST_ABSOLUTE; + fn ILCreateFromPathW(pszPath: PCWSTR) -> *mut ITEMIDLIST; - fn ILFree(pidl: PIDLIST_RELATIVE); + fn ILFree(pidl: *mut ITEMIDLIST); fn SHOpenFolderAndSelectItems( - pidlFolder: PCIDLIST_ABSOLUTE, - cidl: UINT, - apidl: PCUITEMID_CHILD_ARRAY, - dwFlags: DWORD, + pidlFolder: *const ITEMIDLIST, + cidl: u32, + apidl: *const *const ITEMIDLIST, + dwFlags: u32, ) -> HRESULT; }