@@ -1,5 +1,6 @@
use std::{
cell::RefCell,
+ ffi::OsStr,
mem::ManuallyDrop,
path::{Path, PathBuf},
rc::Rc,
@@ -460,13 +461,15 @@ impl Platform for WindowsPlatform {
}
fn open_url(&self, url: &str) {
+ if url.is_empty() {
+ return;
+ }
let url_string = url.to_string();
self.background_executor()
.spawn(async move {
- if url_string.is_empty() {
- return;
- }
- open_target(url_string.as_str());
+ open_target(&url_string)
+ .with_context(|| format!("Opening url: {}", url_string))
+ .log_err();
})
.detach();
}
@@ -514,37 +517,29 @@ impl Platform for WindowsPlatform {
}
fn reveal_path(&self, path: &Path) {
- let Ok(file_full_path) = path.canonicalize() else {
- log::error!("unable to parse file path");
+ if path.as_os_str().is_empty() {
return;
- };
+ }
+ let path = path.to_path_buf();
self.background_executor()
.spawn(async move {
- let Some(path) = file_full_path.to_str() else {
- return;
- };
- if path.is_empty() {
- return;
- }
- open_target_in_explorer(path);
+ open_target_in_explorer(&path)
+ .with_context(|| format!("Revealing path {} in explorer", path.display()))
+ .log_err();
})
.detach();
}
fn open_with_system(&self, path: &Path) {
- let Ok(full_path) = path.canonicalize() else {
- log::error!("unable to parse file full path: {}", path.display());
+ if path.as_os_str().is_empty() {
return;
- };
+ }
+ let path = path.to_path_buf();
self.background_executor()
.spawn(async move {
- let Some(full_path_str) = full_path.to_str() else {
- return;
- };
- if full_path_str.is_empty() {
- return;
- };
- open_target(full_path_str);
+ open_target(&path)
+ .with_context(|| format!("Opening {} with system", path.display()))
+ .log_err();
})
.detach();
}
@@ -735,39 +730,67 @@ pub(crate) struct WindowCreationInfo {
pub(crate) disable_direct_composition: bool,
}
-fn open_target(target: &str) {
- unsafe {
- let ret = ShellExecuteW(
+fn open_target(target: impl AsRef<OsStr>) -> Result<()> {
+ let target = target.as_ref();
+ let ret = unsafe {
+ ShellExecuteW(
None,
windows::core::w!("open"),
&HSTRING::from(target),
None,
None,
SW_SHOWDEFAULT,
- );
- if ret.0 as isize <= 32 {
- log::error!("Unable to open target: {}", std::io::Error::last_os_error());
- }
+ )
+ };
+ if ret.0 as isize <= 32 {
+ Err(anyhow::anyhow!(
+ "Unable to open target: {}",
+ std::io::Error::last_os_error()
+ ))
+ } else {
+ Ok(())
}
}
-fn open_target_in_explorer(target: &str) {
+fn open_target_in_explorer(target: &Path) -> Result<()> {
+ let dir = target.parent().context("No parent folder found")?;
+ let desktop = unsafe { SHGetDesktopFolder()? };
+
+ let mut dir_item = std::ptr::null_mut();
unsafe {
- let ret = ShellExecuteW(
+ desktop.ParseDisplayName(
+ HWND::default(),
None,
- windows::core::w!("open"),
- windows::core::w!("explorer.exe"),
- &HSTRING::from(format!("/select,{}", target).as_str()),
+ &HSTRING::from(dir),
None,
- SW_SHOWDEFAULT,
- );
- if ret.0 as isize <= 32 {
- log::error!(
- "Unable to open target in explorer: {}",
- std::io::Error::last_os_error()
- );
- }
+ &mut dir_item,
+ std::ptr::null_mut(),
+ )?;
}
+
+ let mut file_item = std::ptr::null_mut();
+ unsafe {
+ desktop.ParseDisplayName(
+ HWND::default(),
+ None,
+ &HSTRING::from(target),
+ None,
+ &mut file_item,
+ std::ptr::null_mut(),
+ )?;
+ }
+
+ let highlight = [file_item as *const _];
+ unsafe { SHOpenFolderAndSelectItems(dir_item as _, Some(&highlight), 0) }.or_else(|err| {
+ if err.code().0 == ERROR_FILE_NOT_FOUND.0 as i32 {
+ // On some systems, the above call mysteriously fails with "file not
+ // found" even though the file is there. In these cases, ShellExecute()
+ // seems to work as a fallback (although it won't select the file).
+ open_target(dir).context("Opening target parent folder")
+ } else {
+ Err(anyhow::anyhow!("Can not open target path: {}", err))
+ }
+ })
}
fn file_open_dialog(