add show_item_in_dir (windows impl)

pull/2019/head
amrbashir 9 months ago
parent b9ced5422b
commit 6766bfdbd4
No known key found for this signature in database
GPG Key ID: BBD7A47A2003FF33

22
Cargo.lock generated

@ -6584,6 +6584,7 @@ dependencies = [
name = "tauri-plugin-opener" name = "tauri-plugin-opener"
version = "2.0.0" version = "2.0.0"
dependencies = [ dependencies = [
"dunce",
"open", "open",
"regex", "regex",
"schemars", "schemars",
@ -6594,6 +6595,7 @@ dependencies = [
"thiserror", "thiserror",
"url", "url",
"urlpattern", "urlpattern",
"windows 0.54.0",
] ]
[[package]] [[package]]
@ -7942,6 +7944,16 @@ dependencies = [
"windows_x86_64_msvc 0.36.1", "windows_x86_64_msvc 0.36.1",
] ]
[[package]]
name = "windows"
version = "0.54.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9252e5725dbed82865af151df558e754e4a3c2c30818359eb17465f1346a1b49"
dependencies = [
"windows-core 0.54.0",
"windows-targets 0.52.6",
]
[[package]] [[package]]
name = "windows" name = "windows"
version = "0.56.0" version = "0.56.0"
@ -7971,6 +7983,16 @@ dependencies = [
"windows-targets 0.52.6", "windows-targets 0.52.6",
] ]
[[package]]
name = "windows-core"
version = "0.54.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12661b9c89351d684a50a8a643ce5f608e20243b9fb84687800163429f161d65"
dependencies = [
"windows-result 0.1.2",
"windows-targets 0.52.6",
]
[[package]] [[package]]
name = "windows-core" name = "windows-core"
version = "0.56.0" version = "0.56.0"

@ -38,3 +38,16 @@ open = { version = "5", features = ["shellexecute-on-windows"] }
urlpattern = { workspace = true } urlpattern = { workspace = true }
regex = "1" regex = "1"
url = { workspace = true } url = { workspace = true }
[target."cfg(windows)".dependencies]
dunce = { workspace = true }
[target."cfg(windows)".dependencies.windows]
version = "0.54"
features = [
"Win32_Foundation",
"Win32_UI_Shell_Common",
"Win32_UI_WindowsAndMessaging",
"Win32_System_Com",
"Win32_System_Registry",
]

@ -2,6 +2,8 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
use std::path::PathBuf;
use serde::{Serialize, Serializer}; use serde::{Serialize, Serializer};
#[derive(Debug, thiserror::Error)] #[derive(Debug, thiserror::Error)]
@ -19,6 +21,15 @@ pub enum Error {
UnknownProgramName(String), UnknownProgramName(String),
#[error("Not allowed to open {0}")] #[error("Not allowed to open {0}")]
NotAllowed(String), NotAllowed(String),
/// API not supported on the current platform
#[error("API not supported on the current platform")]
UnsupportedPlatform,
#[error(transparent)]
#[cfg(windows)]
Win32Error(#[from] windows::core::Error),
/// Path doesn't have a parent.
#[error("Path doesn't have a parent: {0}")]
NoParent(PathBuf),
} }
impl Serialize for Error { impl Serialize for Error {

@ -2,6 +2,8 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
use std::path::Path;
use tauri::{ use tauri::{
plugin::{Builder, TauriPlugin}, plugin::{Builder, TauriPlugin},
AppHandle, Manager, Runtime, AppHandle, Manager, Runtime,
@ -19,10 +21,14 @@ mod error;
mod open; mod open;
mod scope; mod scope;
mod scope_entry; mod scope_entry;
mod show_item_in_dir;
pub use error::Error; pub use error::Error;
type Result<T> = std::result::Result<T, Error>; type Result<T> = std::result::Result<T, Error>;
pub use open::{open, Program};
pub use show_item_in_dir::show_item_in_dir;
pub struct Opener<R: Runtime> { pub struct Opener<R: Runtime> {
#[allow(dead_code)] #[allow(dead_code)]
app: AppHandle<R>, app: AppHandle<R>,
@ -44,6 +50,10 @@ impl<R: Runtime> Opener<R> {
.run_mobile_plugin("open", path.into()) .run_mobile_plugin("open", path.into())
.map_err(Into::into) .map_err(Into::into)
} }
pub fn show_item_in_dir<P: AsRef<Path>>(&self, p: P) -> Result<()> {
show_item_in_dir::show_item_in_dir(p)
}
} }
/// Extensions to [`tauri::App`], [`tauri::AppHandle`], [`tauri::WebviewWindow`], [`tauri::Webview`] and [`tauri::Window`] to access the opener APIs. /// Extensions to [`tauri::App`], [`tauri::AppHandle`], [`tauri::WebviewWindow`], [`tauri::Webview`] and [`tauri::Window`] to access the opener APIs.

@ -0,0 +1,120 @@
use std::path::Path;
use std::path::PathBuf;
/// Show
///
/// ## Platform-specific:
///
/// - **Android / iOS:** Unsupported.
pub fn show_item_in_dir<P: AsRef<Path>>(p: P) -> crate::Result<()> {
let p = p.as_ref().canonicalize()?;
#[cfg(any(
windows,
target_os = "macos",
target_os = "linux",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd"
))]
return imp::show_item_in_dir(p);
#[cfg(not(any(
windows,
target_os = "macos",
target_os = "linux",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd"
)))]
Err(crate::Error::UnsupportedPlatform)
}
#[cfg(windows)]
mod imp {
use super::*;
use windows::{
core::{w, HSTRING, PCWSTR},
Win32::{
Foundation::ERROR_FILE_NOT_FOUND,
System::Com::CoInitialize,
UI::{
Shell::{
ILCreateFromPathW, ILFree, SHOpenFolderAndSelectItems, ShellExecuteExW,
SHELLEXECUTEINFOW,
},
WindowsAndMessaging::SW_SHOWNORMAL,
},
},
};
pub fn show_item_in_dir(p: PathBuf) -> crate::Result<()> {
let file = dunce::simplified(&p);
let _ = unsafe { CoInitialize(None) };
let dir = file
.parent()
.ok_or_else(|| crate::Error::NoParent(file.to_path_buf()))?;
let dir = HSTRING::from(dir);
let dir_item = unsafe { ILCreateFromPathW(PCWSTR::from_raw(dir.as_ptr())) };
let file_h = HSTRING::from(file);
let file_item = unsafe { ILCreateFromPathW(PCWSTR::from_raw(file_h.as_ptr())) };
unsafe {
if let Err(e) = SHOpenFolderAndSelectItems(dir_item, Some(&[file_item]), 0) {
if e.code().0 == ERROR_FILE_NOT_FOUND.0 as i32 {
let is_dir = std::fs::metadata(file).map(|f| f.is_dir()).unwrap_or(false);
let mut info = SHELLEXECUTEINFOW {
cbSize: std::mem::size_of::<SHELLEXECUTEINFOW>() as _,
nShow: SW_SHOWNORMAL.0,
lpVerb: if is_dir {
w!("explore")
} else {
PCWSTR::null()
},
lpClass: if is_dir { w!("folder") } else { PCWSTR::null() },
lpFile: PCWSTR(file_h.as_ptr()),
..std::mem::zeroed()
};
ShellExecuteExW(&mut info)?;
}
}
}
unsafe {
ILFree(Some(dir_item));
ILFree(Some(file_item));
}
Ok(())
}
}
#[cfg(any(
target_os = "linux",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd"
))]
mod imp {
use super::*;
pub fn show_item_in_dir(p: PathBuf) -> crate::Result<()> {
Ok(())
}
}
#[cfg(target_os = "macos")]
mod imp {
use super::*;
pub fn show_item_in_dir(p: PathBuf) -> crate::Result<()> {}
}
Loading…
Cancel
Save