Skip to content

Commit 74fd8ec

Browse files
committed
fix: add shellexecute-on-windows feature.
That way, it's possible to toggle on a feature that might cause issues in some dependency trees that contain `flate2` with `zlib-ng` backend.
1 parent 8f26da4 commit 74fd8ec

File tree

4 files changed

+33
-12
lines changed

4 files changed

+33
-12
lines changed

.github/workflows/cross-platform-testing.yml

+3
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@ jobs:
7272
echo "target flag is: ${{ env.TARGET_FLAGS }}"
7373
echo "target dir is: ${{ env.TARGET_DIR }}"
7474
75+
- name: Build with all features
76+
if: startsWith(matrix.os, 'windows')
77+
run: ${{ env.CARGO }} build ${{ env.TARGET_FLAGS }} --all-features
7578
- name: Build (and link)
7679
run: ${{ env.CARGO }} build ${{ env.TARGET_FLAGS }}
7780
- name: Run tests

Cargo.toml

+11
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,17 @@ keywords = ["open", "xdg-open", "start", "launch"]
1212
include = ["src/**/*", "LICENSE.md", "README.md", "changelog.md"]
1313
rust-version = "1.62"
1414

15+
[features]
16+
## If enabled, link to `shell32` on Windows and use `ShellExecuteW` intead of a command invocation
17+
## when launching something in 'detached' mode.
18+
## That way, it should be possible to open currently opened (for writing) files as well.
19+
##
20+
## However, linking errors have been observed due to it where the one external function used here
21+
## couldn't be found, which is why it was put behind a feature toggle.
22+
##
23+
## This feature is only effective on Windows.
24+
shellexecute-on-windows = []
25+
1526
[[bin]]
1627
test = false
1728
doc = false

src/lib.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ pub fn with_in_background<T: AsRef<OsStr>>(
237237
///
238238
/// See documentation of [`that()`] for more details.
239239
pub fn that_detached(path: impl AsRef<OsStr>) -> io::Result<()> {
240-
#[cfg(not(windows))]
240+
#[cfg(any(not(feature = "shellexecute-on-windows"), not(windows)))]
241241
{
242242
let mut last_err = None;
243243
for mut cmd in commands(path) {
@@ -251,7 +251,7 @@ pub fn that_detached(path: impl AsRef<OsStr>) -> io::Result<()> {
251251
Err(last_err.expect("no launcher worked, at least one error"))
252252
}
253253

254-
#[cfg(windows)]
254+
#[cfg(all(windows, feature = "shellexecute-on-windows"))]
255255
{
256256
windows::that_detached(path)
257257
}
@@ -263,13 +263,13 @@ pub fn that_detached(path: impl AsRef<OsStr>) -> io::Result<()> {
263263
///
264264
/// See documentation of [`with()`] for more details.
265265
pub fn with_detached<T: AsRef<OsStr>>(path: T, app: impl Into<String>) -> io::Result<()> {
266-
#[cfg(not(windows))]
266+
#[cfg(any(not(feature = "shellexecute-on-windows"), not(windows)))]
267267
{
268268
let mut cmd = with_command(path, app);
269269
cmd.spawn_detached()
270270
}
271271

272-
#[cfg(windows)]
272+
#[cfg(all(windows, feature = "shellexecute-on-windows"))]
273273
{
274274
windows::with_detached(path, app)
275275
}

src/windows.rs

+15-8
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
use std::{
22
ffi::{OsStr, OsString},
3-
io, iter,
4-
os::windows::ffi::OsStrExt,
53
process::Command,
6-
ptr,
74
};
85

96
use std::os::windows::process::CommandExt;
@@ -39,6 +36,7 @@ fn wrap_in_quotes<T: AsRef<OsStr>>(path: T) -> OsString {
3936
result
4037
}
4138

39+
#[cfg(feature = "shellexecute-on-windows")]
4240
pub fn that_detached<T: AsRef<OsStr>>(path: T) -> std::io::Result<()> {
4341
let path = wide(path);
4442

@@ -47,13 +45,14 @@ pub fn that_detached<T: AsRef<OsStr>>(path: T) -> std::io::Result<()> {
4745
0,
4846
ffi::OPEN,
4947
path.as_ptr(),
50-
ptr::null(),
51-
ptr::null(),
48+
std::ptr::null(),
49+
std::ptr::null(),
5250
ffi::SW_SHOW,
5351
)
5452
}
5553
}
5654

55+
#[cfg(feature = "shellexecute-on-windows")]
5756
pub fn with_detached<T: AsRef<OsStr>>(path: T, app: impl Into<String>) -> std::io::Result<()> {
5857
let app = wide(app.into());
5958
let path = wide(path);
@@ -64,21 +63,28 @@ pub fn with_detached<T: AsRef<OsStr>>(path: T, app: impl Into<String>) -> std::i
6463
ffi::OPEN,
6564
app.as_ptr(),
6665
path.as_ptr(),
67-
ptr::null(),
66+
std::ptr::null(),
6867
ffi::SW_SHOW,
6968
)
7069
}
7170
}
7271

7372
/// Encodes as wide and adds a null character.
73+
#[cfg(feature = "shellexecute-on-windows")]
7474
fn wide<T: AsRef<OsStr>>(input: T) -> Vec<u16> {
75-
input.as_ref().encode_wide().chain(iter::once(0)).collect()
75+
use std::os::windows::ffi::OsStrExt;
76+
input
77+
.as_ref()
78+
.encode_wide()
79+
.chain(std::iter::once(0))
80+
.collect()
7681
}
7782

7883
/// Performs an operation on a specified file.
7984
///
8085
/// <https://learn.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shellexecutew>
8186
#[allow(non_snake_case)]
87+
#[cfg(feature = "shellexecute-on-windows")]
8288
pub unsafe fn ShellExecuteW(
8389
hwnd: isize,
8490
lpoperation: *const u16,
@@ -101,10 +107,11 @@ pub unsafe fn ShellExecuteW(
101107
if hr > 32 {
102108
Ok(())
103109
} else {
104-
Err(io::Error::last_os_error())
110+
Err(std::io::Error::last_os_error())
105111
}
106112
}
107113

114+
#[cfg(feature = "shellexecute-on-windows")]
108115
mod ffi {
109116
/// Activates the window and displays it in its current size and position.
110117
///

0 commit comments

Comments
 (0)