From 9fb4494a96d8384f8d0cb189e0234b6369d7a83b Mon Sep 17 00:00:00 2001 From: Hartley McGuire Date: Mon, 18 Dec 2023 22:51:02 -0500 Subject: [PATCH 1/2] Replace winapi dependency with windows Since normpath was [added][1], opener has depended on both winapi (directly) and windows-sys (transitively). This commit replaces usage of winapi with the windows crate so that it only depends on a single windows API crate. Additionally, the windows crate includes some functions that were manually linked in opener, so those manual links were able to be cleaned up. [1]: 3b48ee084300ba883bed11259d978fa989ffaed8 --- opener/Cargo.toml | 10 +++-- opener/src/windows.rs | 23 ++++++------ opener/src/windows/reveal.rs | 72 +++++++++--------------------------- 3 files changed, 36 insertions(+), 69 deletions(-) diff --git a/opener/Cargo.toml b/opener/Cargo.toml index 22e0ca6..ad196ad 100644 --- a/opener/Cargo.toml +++ b/opener/Cargo.toml @@ -19,8 +19,8 @@ maintenance = { status = "passively-maintained" } reveal = [ "dep:url", "dep:dbus", - "winapi/shtypes", - "winapi/objbase", + "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", 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..af93d0a 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) }?; -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)) - } -} + let result = create_and_open_item_list(path); -struct ItemIdList(PIDLIST_ABSOLUTE); + unsafe { CoUninitialize() }; -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)) - } - } + Ok(result?) } -impl Drop for ItemIdList { - fn drop(&mut self) { - unsafe { ILFree(self.0) } - } -} +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())?; + + let item_id_list = unsafe { ILCreateFromPathW(PCWSTR::from_raw(path.as_ptr())) }; -#[link(name = "Shell32")] -extern "C" { - fn ILCreateFromPathW(pszPath: PCWSTR) -> PIDLIST_ABSOLUTE; + let result = unsafe { SHOpenFolderAndSelectItems(item_id_list, None, 0) }; - fn ILFree(pidl: PIDLIST_RELATIVE); + unsafe { ILFree(Some(item_id_list)) }; - fn SHOpenFolderAndSelectItems( - pidlFolder: PCIDLIST_ABSOLUTE, - cidl: UINT, - apidl: PCUITEMID_CHILD_ARRAY, - dwFlags: DWORD, - ) -> HRESULT; + Ok(result?) } From c4ad5579fe1cf53337c2ce0c4f1c118d7df34349 Mon Sep 17 00:00:00 2001 From: Brian Bowman Date: Mon, 22 Jan 2024 14:03:51 -0600 Subject: [PATCH 2/2] Fix nits --- opener/Cargo.toml | 12 ++++++------ opener/src/windows/reveal.rs | 24 ++++++++++++------------ 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/opener/Cargo.toml b/opener/Cargo.toml index ad196ad..86256af 100644 --- a/opener/Cargo.toml +++ b/opener/Cargo.toml @@ -17,10 +17,10 @@ maintenance = { status = "passively-maintained" } [features] reveal = [ - "dep:url", - "dep:dbus", - "windows/Win32_System_Com", - "windows/Win32_UI_Shell_Common" + "dep:url", + "dep:dbus", + "windows/Win32_System_Com", + "windows/Win32_UI_Shell_Common", ] [dev-dependencies] @@ -33,10 +33,10 @@ url = { version = "2", optional = true } [target.'cfg(windows)'.dependencies] normpath = "1" -windows = { version = "0", features = [ +windows = { version = "0.52", features = [ "Win32_Foundation", "Win32_UI_Shell", - "Win32_UI_WindowsAndMessaging" + "Win32_UI_WindowsAndMessaging", ] } [package.metadata.docs.rs] diff --git a/opener/src/windows/reveal.rs b/opener/src/windows/reveal.rs index af93d0a..0614004 100644 --- a/opener/src/windows/reveal.rs +++ b/opener/src/windows/reveal.rs @@ -17,13 +17,13 @@ pub(crate) fn reveal(path: &Path) -> Result<(), OpenError> { } fn reveal_in_thread(path: &Path) -> io::Result<()> { - unsafe { CoInitializeEx(None, COINIT_MULTITHREADED) }?; + unsafe { + CoInitializeEx(None, COINIT_MULTITHREADED)?; + let result = create_and_open_item_list(path); + CoUninitialize(); - let result = create_and_open_item_list(path); - - unsafe { CoUninitialize() }; - - Ok(result?) + result + } } fn create_and_open_item_list(path: &Path) -> io::Result<()> { @@ -32,11 +32,11 @@ fn create_and_open_item_list(path: &Path) -> io::Result<()> { // so we use the normpath crate instead. let path = convert_path(path.normalize()?.as_os_str())?; - let item_id_list = unsafe { ILCreateFromPathW(PCWSTR::from_raw(path.as_ptr())) }; - - let result = unsafe { SHOpenFolderAndSelectItems(item_id_list, None, 0) }; - - unsafe { ILFree(Some(item_id_list)) }; + 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)); - Ok(result?) + Ok(result?) + } }