Skip to content

Commit

Permalink
Merge branch 'validate-linkage'
Browse files Browse the repository at this point in the history
  • Loading branch information
Byron committed Mar 3, 2024
2 parents 21a73ee + 74fd8ec commit 59886df
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 13 deletions.
15 changes: 14 additions & 1 deletion .github/workflows/cross-platform-testing.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
RUST_BACKTRACE: 1
strategy:
matrix:
build: [linux, linux-arm, macos, win-msvc, win-gnu]
build: [ linux, linux-arm, macos, win-msvc, win-gnu, win32-gnu, win32-msvc ]
include:
- build: linux
os: ubuntu-latest
Expand All @@ -42,6 +42,14 @@ jobs:
os: windows-2019
rust: stable
target: x86_64-pc-windows-gnu
- build: win32-gnu
os: windows-latest
rust: stable
target: i686-pc-windows-gnu
- build: win32-msvc
os: windows-latest
rust: stable
target: i686-pc-windows-msvc

steps:
- name: Checkout repository
Expand All @@ -64,6 +72,11 @@ jobs:
echo "target flag is: ${{ env.TARGET_FLAGS }}"
echo "target dir is: ${{ env.TARGET_DIR }}"
- name: Build with all features
if: startsWith(matrix.os, 'windows')
run: ${{ env.CARGO }} build ${{ env.TARGET_FLAGS }} --all-features
- name: Build (and link)
run: ${{ env.CARGO }} build ${{ env.TARGET_FLAGS }}
- name: Run tests
run: ${{ env.CARGO }} test ${{ env.TARGET_FLAGS }}
- name: Run fmt
Expand Down
11 changes: 11 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,17 @@ keywords = ["open", "xdg-open", "start", "launch"]
include = ["src/**/*", "LICENSE.md", "README.md", "changelog.md"]
rust-version = "1.62"

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

[[bin]]
test = false
doc = false
Expand Down
8 changes: 4 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ pub fn with_in_background<T: AsRef<OsStr>>(
///
/// See documentation of [`that()`] for more details.
pub fn that_detached(path: impl AsRef<OsStr>) -> io::Result<()> {
#[cfg(not(windows))]
#[cfg(any(not(feature = "shellexecute-on-windows"), not(windows)))]
{
let mut last_err = None;
for mut cmd in commands(path) {
Expand All @@ -251,7 +251,7 @@ pub fn that_detached(path: impl AsRef<OsStr>) -> io::Result<()> {
Err(last_err.expect("no launcher worked, at least one error"))
}

#[cfg(windows)]
#[cfg(all(windows, feature = "shellexecute-on-windows"))]
{
windows::that_detached(path)
}
Expand All @@ -263,13 +263,13 @@ pub fn that_detached(path: impl AsRef<OsStr>) -> io::Result<()> {
///
/// See documentation of [`with()`] for more details.
pub fn with_detached<T: AsRef<OsStr>>(path: T, app: impl Into<String>) -> io::Result<()> {
#[cfg(not(windows))]
#[cfg(any(not(feature = "shellexecute-on-windows"), not(windows)))]
{
let mut cmd = with_command(path, app);
cmd.spawn_detached()
}

#[cfg(windows)]
#[cfg(all(windows, feature = "shellexecute-on-windows"))]
{
windows::with_detached(path, app)
}
Expand Down
23 changes: 15 additions & 8 deletions src/windows.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
use std::{
ffi::{OsStr, OsString},
io, iter,
os::windows::ffi::OsStrExt,
process::Command,
ptr,
};

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

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

Expand All @@ -47,13 +45,14 @@ pub fn that_detached<T: AsRef<OsStr>>(path: T) -> std::io::Result<()> {
0,
ffi::OPEN,
path.as_ptr(),
ptr::null(),
ptr::null(),
std::ptr::null(),
std::ptr::null(),
ffi::SW_SHOW,
)
}
}

#[cfg(feature = "shellexecute-on-windows")]
pub fn with_detached<T: AsRef<OsStr>>(path: T, app: impl Into<String>) -> std::io::Result<()> {
let app = wide(app.into());
let path = wide(path);
Expand All @@ -64,21 +63,28 @@ pub fn with_detached<T: AsRef<OsStr>>(path: T, app: impl Into<String>) -> std::i
ffi::OPEN,
app.as_ptr(),
path.as_ptr(),
ptr::null(),
std::ptr::null(),
ffi::SW_SHOW,
)
}
}

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

/// Performs an operation on a specified file.
///
/// <https://learn.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shellexecutew>
#[allow(non_snake_case)]
#[cfg(feature = "shellexecute-on-windows")]
pub unsafe fn ShellExecuteW(
hwnd: isize,
lpoperation: *const u16,
Expand All @@ -101,10 +107,11 @@ pub unsafe fn ShellExecuteW(
if hr > 32 {
Ok(())
} else {
Err(io::Error::last_os_error())
Err(std::io::Error::last_os_error())
}
}

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

0 comments on commit 59886df

Please sign in to comment.