mirror of
https://github.com/tauri-apps/plugins-workspace.git
synced 2026-10-10 22:38:44 +02:00
fix(single-instance): do not rely on | as arg separator on Windows (#3686)
This commit is contained in:
1 parent
659f222742
commit
b53d198461
2 files changed
+46
-20
No files matched your search
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"single-instance": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
On Windows, an argument containing a `|` is no longer split into several arguments when it is forwarded to the running instance.
|
||||||
@@ -6,7 +6,6 @@
|
|||||||
use crate::semver_compat::semver_compat_string;
|
use crate::semver_compat::semver_compat_string;
|
||||||
|
|
||||||
use crate::SingleInstanceCallback;
|
use crate::SingleInstanceCallback;
|
||||||
use std::ffi::CStr;
|
|
||||||
use tauri::{
|
use tauri::{
|
||||||
AppHandle, Manager, RunEvent, Runtime,
|
AppHandle, Manager, RunEvent, Runtime,
|
||||||
plugin::{self, TauriPlugin},
|
plugin::{self, TauriPlugin},
|
||||||
@@ -27,7 +26,12 @@ use windows_sys::Win32::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// TODO(v3): remove this
|
||||||
|
/// Legacy payload: cwd and arguments joined by `|`, which splits any argument containing a `|`.
|
||||||
|
/// Still accepted from second instances running an older version of the plugin.
|
||||||
const WMCOPYDATA_SINGLE_INSTANCE_DATA: usize = 1542;
|
const WMCOPYDATA_SINGLE_INSTANCE_DATA: usize = 1542;
|
||||||
|
/// Cwd and arguments separated by NUL, without a terminator.
|
||||||
|
const WMCOPYDATA_SINGLE_INSTANCE_DATA_NUL: usize = 1543;
|
||||||
|
|
||||||
/// How long the second instance waits for the first instance to take its arguments.
|
/// How long the second instance waits for the first instance to take its arguments.
|
||||||
const FORWARD_TIMEOUT_MS: u32 = 10_000;
|
const FORWARD_TIMEOUT_MS: u32 = 10_000;
|
||||||
@@ -88,19 +92,20 @@ pub fn init<R: Runtime>(callback: Box<SingleInstanceCallback<R>>) -> TauriPlugin
|
|||||||
AllowSetForegroundWindow(pid);
|
AllowSetForegroundWindow(pid);
|
||||||
}
|
}
|
||||||
|
|
||||||
let cwd = std::env::current_dir().unwrap_or_default();
|
// Neither the cwd nor an argument can contain a NUL on Windows, so it
|
||||||
let cwd = cwd.to_string_lossy();
|
// separates them unambiguously.
|
||||||
|
let mut data = std::env::current_dir()
|
||||||
let args = std::env::args_os()
|
.unwrap_or_default()
|
||||||
.map(|arg| arg.to_string_lossy().into_owned())
|
.to_string_lossy()
|
||||||
.collect::<Vec<String>>()
|
.into_owned();
|
||||||
.join("|");
|
for arg in std::env::args_os() {
|
||||||
|
data.push('\0');
|
||||||
let data = format!("{cwd}|{args}\0",);
|
data.push_str(&arg.to_string_lossy());
|
||||||
|
}
|
||||||
|
|
||||||
let bytes = data.as_bytes();
|
let bytes = data.as_bytes();
|
||||||
let cds = COPYDATASTRUCT {
|
let cds = COPYDATASTRUCT {
|
||||||
dwData: WMCOPYDATA_SINGLE_INSTANCE_DATA,
|
dwData: WMCOPYDATA_SINGLE_INSTANCE_DATA_NUL,
|
||||||
cbData: bytes.len() as _,
|
cbData: bytes.len() as _,
|
||||||
lpData: bytes.as_ptr() as _,
|
lpData: bytes.as_ptr() as _,
|
||||||
};
|
};
|
||||||
@@ -174,17 +179,33 @@ unsafe extern "system" fn single_instance_window_proc<R: Runtime>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
WM_COPYDATA => {
|
WM_COPYDATA => {
|
||||||
let cds_ptr = lparam as *const COPYDATASTRUCT;
|
let cds = unsafe { &*(lparam as *const COPYDATASTRUCT) };
|
||||||
if unsafe { (*cds_ptr).dwData == WMCOPYDATA_SINGLE_INSTANCE_DATA } {
|
let separator = match cds.dwData {
|
||||||
let userdata = unsafe { UserData::<R>::from_hwnd(hwnd) };
|
WMCOPYDATA_SINGLE_INSTANCE_DATA_NUL => '\0',
|
||||||
|
WMCOPYDATA_SINGLE_INSTANCE_DATA => '|',
|
||||||
|
_ => return 1,
|
||||||
|
};
|
||||||
|
|
||||||
let data = unsafe { CStr::from_ptr((*cds_ptr).lpData as _).to_string_lossy() };
|
let bytes = if cds.lpData.is_null() {
|
||||||
let mut s = data.split('|');
|
&[][..]
|
||||||
let cwd = s.next().unwrap();
|
} else {
|
||||||
let args = s.map(|s| s.to_string()).collect();
|
unsafe { std::slice::from_raw_parts(cds.lpData as *const u8, cds.cbData as _) }
|
||||||
|
};
|
||||||
|
// The legacy format ends with a NUL terminator. The new one doesn't: a trailing NUL
|
||||||
|
// there precedes an empty last argument.
|
||||||
|
let bytes = if separator == '|' {
|
||||||
|
bytes.split(|b| *b == 0).next().unwrap_or_default()
|
||||||
|
} else {
|
||||||
|
bytes
|
||||||
|
};
|
||||||
|
let data = String::from_utf8_lossy(bytes);
|
||||||
|
|
||||||
userdata.run_callback(args, cwd.to_string());
|
let mut s = data.split(separator);
|
||||||
}
|
let cwd = s.next().unwrap_or_default().to_string();
|
||||||
|
let args = s.map(|s| s.to_string()).collect();
|
||||||
|
|
||||||
|
let userdata = unsafe { UserData::<R>::from_hwnd(hwnd) };
|
||||||
|
userdata.run_callback(args, cwd);
|
||||||
1
|
1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user