mirror of
https://github.com/BTMuli/TeyvatGuide.git
synced 2026-03-30 06:19:45 +08:00
73 lines
2.3 KiB
Rust
73 lines
2.3 KiB
Rust
//! 重启提权相关处理
|
||
//! @since Beta v0.9.1
|
||
#![cfg(target_os = "windows")]
|
||
|
||
use std::ptr::null_mut;
|
||
use std::time::Duration;
|
||
use tauri::AppHandle;
|
||
use widestring::U16CString;
|
||
use windows_sys::Win32::Foundation::{HANDLE, HWND};
|
||
use windows_sys::Win32::Storage::FileSystem::SYNCHRONIZE;
|
||
use windows_sys::Win32::System::Threading::{INFINITE, OpenProcess, WaitForSingleObject};
|
||
use windows_sys::Win32::UI::Shell::ShellExecuteW;
|
||
use windows_sys::Win32::UI::WindowsAndMessaging::SW_SHOWNORMAL;
|
||
|
||
/// 带参数启动(使用 ShellExecuteW + runas)
|
||
fn shell_runas_with_args(args: &str) -> Result<(), String> {
|
||
let exe_path = std::env::current_exe().map_err(|e| e.to_string())?;
|
||
|
||
let exe_wide =
|
||
U16CString::from_os_str(exe_path.as_os_str()).map_err(|e| format!("路径转换失败: {e}"))?;
|
||
let args_wide = U16CString::from_str(args).map_err(|e| format!("参数转换失败: {e}"))?;
|
||
let cwd_wide = exe_path
|
||
.parent()
|
||
.map(|p| U16CString::from_os_str(p.as_os_str()))
|
||
.transpose()
|
||
.map_err(|e| format!("路径转换失败: {e}"))?
|
||
.unwrap_or_else(|| U16CString::from_str("").unwrap());
|
||
|
||
let verb = U16CString::from_str("runas").unwrap();
|
||
|
||
unsafe {
|
||
let result = ShellExecuteW(
|
||
0 as HWND,
|
||
verb.as_ptr(),
|
||
exe_wide.as_ptr(),
|
||
args_wide.as_ptr(),
|
||
if cwd_wide.len() > 1 { cwd_wide.as_ptr() } else { null_mut() },
|
||
SW_SHOWNORMAL,
|
||
);
|
||
if (result as usize) > 32 { Ok(()) } else { Err("ShellExecuteW runas 启动失败".into()) }
|
||
}
|
||
}
|
||
|
||
/// 等待父进程退出(释放单例锁)后,再以管理员身份启动新实例
|
||
pub fn run_watchdog(parent_pid: u32, args_to_pass: &str) -> Result<(), String> {
|
||
let handle: HANDLE = unsafe { OpenProcess(SYNCHRONIZE, 0, parent_pid) };
|
||
if handle.is_null() {
|
||
std::thread::sleep(Duration::from_millis(300));
|
||
} else {
|
||
unsafe {
|
||
WaitForSingleObject(handle, INFINITE);
|
||
}
|
||
}
|
||
|
||
shell_runas_with_args(args_to_pass)
|
||
}
|
||
|
||
/// 以管理员权限重启应用
|
||
#[tauri::command]
|
||
pub fn run_with_admin(app_handle: AppHandle) -> Result<(), String> {
|
||
let parent_pid = std::process::id();
|
||
let exe = std::env::current_exe().map_err(|e| e.to_string())?;
|
||
let mut cmd = std::process::Command::new(exe);
|
||
cmd
|
||
.arg("--watchdog")
|
||
.arg(format!("--ppid={}", parent_pid))
|
||
.spawn()
|
||
.map_err(|e| format!("spawn watchdog failed: {e}"))?;
|
||
|
||
app_handle.exit(0);
|
||
Ok(())
|
||
}
|