diff --git a/opener/Cargo.toml b/opener/Cargo.toml index 22e0ca6..86256af 100644 --- a/opener/Cargo.toml +++ b/opener/Cargo.toml @@ -17,10 +17,10 @@ maintenance = { status = "passively-maintained" } [features] reveal = [ - "dep:url", - "dep:dbus", - "winapi/shtypes", - "winapi/objbase", + "dep:url", + "dep:dbus", + "windows/Win32_System_Com", + "windows/Win32_UI_Shell_Common", ] [dev-dependencies] @@ -33,7 +33,11 @@ url = { version = "2", optional = true } [target.'cfg(windows)'.dependencies] normpath = "1" -winapi = { version = "0.3", features = ["shellapi"] } +windows = { 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..d150827 100644 --- a/opener/src/windows.rs +++ b/opener/src/windows.rs @@ -1,11 +1,13 @@ use crate::OpenError; use normpath::PathExt; use std::ffi::OsStr; +use std::io; 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::core::{w, PCWSTR}; +use windows::Win32::Foundation::HWND; +use windows::Win32::UI::Shell::ShellExecuteW; +use windows::Win32::UI::WindowsAndMessaging::SW_SHOW; #[cfg(feature = "reveal")] mod reveal; @@ -27,21 +29,18 @@ 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(), - operation.as_ptr(), - path.as_ptr(), - ptr::null(), - ptr::null(), + HWND(0), + w!("open"), + PCWSTR::from_raw(path.as_ptr()), + PCWSTR::null(), + PCWSTR::null(), SW_SHOW, ) }; - if result as c_int > 32 { + if result.0 > 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..0614004 100644 --- a/opener/src/windows/reveal.rs +++ b/opener/src/windows/reveal.rs @@ -2,15 +2,10 @@ 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 std::{io, thread}; +use windows::core::PCWSTR; +use windows::Win32::System::Com::{CoInitializeEx, CoUninitialize, COINIT_MULTITHREADED}; +use windows::Win32::UI::Shell::{ILCreateFromPathW, ILFree, SHOpenFolderAndSelectItems}; pub(crate) fn reveal(path: &Path) -> Result<(), OpenError> { let path = path.to_owned(); @@ -22,57 +17,26 @@ 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(()) -} + unsafe { + CoInitializeEx(None, COINIT_MULTITHREADED)?; + let result = create_and_open_item_list(path); + CoUninitialize(); -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)) + result } } -struct ItemIdList(PIDLIST_ABSOLUTE); +fn create_and_open_item_list(path: &Path) -> io::Result<()> { + // 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())?; -impl ItemIdList { - fn new(path: &Path) -> io::Result { - // 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()) - } else { - Ok(ItemIdList(result)) - } - } -} + unsafe { + let item_id_list = ILCreateFromPathW(PCWSTR::from_raw(path.as_ptr())); + let result = SHOpenFolderAndSelectItems(item_id_list, None, 0); + ILFree(Some(item_id_list)); -impl Drop for ItemIdList { - fn drop(&mut self) { - unsafe { ILFree(self.0) } + Ok(result?) } } - -#[link(name = "Shell32")] -extern "C" { - fn ILCreateFromPathW(pszPath: PCWSTR) -> PIDLIST_ABSOLUTE; - - fn ILFree(pidl: PIDLIST_RELATIVE); - - fn SHOpenFolderAndSelectItems( - pidlFolder: PCIDLIST_ABSOLUTE, - cidl: UINT, - apidl: PCUITEMID_CHILD_ARRAY, - dwFlags: DWORD, - ) -> HRESULT; -}