mirror of
https://github.com/BTMuli/TeyvatGuide.git
synced 2025-12-06 08:32:51 +08:00
♻️ 代码重构提取
This commit is contained in:
@@ -127,90 +127,3 @@ pub fn is_in_admin() -> bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
|
||||||
pub fn shell_runas_with_args(args: &str) -> Result<(), String> {
|
|
||||||
use std::ffi::OsStr;
|
|
||||||
use std::iter::once;
|
|
||||||
use std::os::windows::ffi::OsStrExt;
|
|
||||||
use std::ptr::null_mut;
|
|
||||||
|
|
||||||
use windows_sys::Win32::Foundation::HWND;
|
|
||||||
use windows_sys::Win32::UI::Shell::ShellExecuteW;
|
|
||||||
use windows_sys::Win32::UI::WindowsAndMessaging::SW_SHOWNORMAL;
|
|
||||||
|
|
||||||
fn to_wide(s: &OsStr) -> Vec<u16> {
|
|
||||||
s.encode_wide().chain(once(0)).collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
let exe_path = std::env::current_exe().map_err(|e| e.to_string())?;
|
|
||||||
let exe_wide = to_wide(exe_path.as_os_str());
|
|
||||||
let args_wide = to_wide(OsStr::new(args));
|
|
||||||
let cwd_wide =
|
|
||||||
exe_path.parent().map(|p| to_wide(p.as_os_str())).unwrap_or_else(|| to_wide(OsStr::new("")));
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
let result = ShellExecuteW(
|
|
||||||
0 as HWND,
|
|
||||||
to_wide(OsStr::new("runas")).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("Failed to ShellExecuteW runas".into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 等待父进程退出(释放单例锁)后,再以管理员身份启动新实例
|
|
||||||
#[cfg(target_os = "windows")]
|
|
||||||
pub fn run_watchdog(parent_pid: u32, args_to_pass: &str) -> Result<(), String> {
|
|
||||||
use std::time::Duration;
|
|
||||||
use windows_sys::Win32::Foundation::HANDLE;
|
|
||||||
use windows_sys::Win32::Storage::FileSystem::SYNCHRONIZE;
|
|
||||||
use windows_sys::Win32::System::Threading::{OpenProcess, WaitForSingleObject, INFINITE};
|
|
||||||
|
|
||||||
// 打开父进程句柄用于等待
|
|
||||||
let handle: HANDLE = unsafe { OpenProcess(SYNCHRONIZE, 0, parent_pid) };
|
|
||||||
if handle == std::ptr::null_mut() {
|
|
||||||
// 如果拿不到句柄,可能父进程已退出,稍作等待后继续
|
|
||||||
std::thread::sleep(Duration::from_millis(300));
|
|
||||||
} else {
|
|
||||||
unsafe {
|
|
||||||
WaitForSingleObject(handle, INFINITE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 父进程已退出 → 触发 UAC 提权启动新实例
|
|
||||||
shell_runas_with_args(args_to_pass)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 以管理员权限重启应用
|
|
||||||
#[tauri::command]
|
|
||||||
pub fn run_with_admin(app_handle: AppHandle) -> Result<(), String> {
|
|
||||||
#[cfg(not(target_os = "windows"))]
|
|
||||||
{
|
|
||||||
return Err("This function is only supported on Windows.".into());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
|
||||||
{
|
|
||||||
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))
|
|
||||||
// 看门狗不加载单例插件(通过参数决定 main 的初始化)
|
|
||||||
.spawn()
|
|
||||||
.map_err(|e| format!("spawn watchdog failed: {e}"))?;
|
|
||||||
|
|
||||||
// 立即退出:单例锁释放
|
|
||||||
app_handle.exit(0);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -6,15 +6,13 @@ mod commands;
|
|||||||
mod plugins;
|
mod plugins;
|
||||||
mod utils;
|
mod utils;
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
|
mod watchdog;
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
mod yae;
|
mod yae;
|
||||||
|
|
||||||
use crate::client::create_mhy_client;
|
use crate::client::create_mhy_client;
|
||||||
use crate::commands::{
|
use crate::commands::{create_window, execute_js, get_dir_size, init_app, is_in_admin};
|
||||||
create_window, execute_js, get_dir_size, init_app, is_in_admin, run_watchdog, run_with_admin,
|
|
||||||
};
|
|
||||||
use crate::plugins::{build_log_plugin, build_si_plugin};
|
use crate::plugins::{build_log_plugin, build_si_plugin};
|
||||||
#[cfg(target_os = "windows")]
|
|
||||||
use crate::yae::call_yae_dll;
|
|
||||||
use tauri::{generate_context, generate_handler, Manager, Window, WindowEvent};
|
use tauri::{generate_context, generate_handler, Manager, Window, WindowEvent};
|
||||||
|
|
||||||
// 窗口事件处理
|
// 窗口事件处理
|
||||||
@@ -56,7 +54,7 @@ pub fn run() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 等父进程退出后再 runas 启动管理员实例,传入 --elevated 标志
|
// 等父进程退出后再 runas 启动管理员实例,传入 --elevated 标志
|
||||||
let _ = run_watchdog(ppid, "--elevated");
|
let _ = watchdog::run_watchdog(ppid, "--elevated");
|
||||||
// 看门狗退出
|
// 看门狗退出
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -93,10 +91,11 @@ pub fn run() {
|
|||||||
execute_js,
|
execute_js,
|
||||||
get_dir_size,
|
get_dir_size,
|
||||||
create_mhy_client,
|
create_mhy_client,
|
||||||
#[cfg(target_os = "windows")]
|
|
||||||
call_yae_dll,
|
|
||||||
is_in_admin,
|
is_in_admin,
|
||||||
run_with_admin
|
#[cfg(target_os = "windows")]
|
||||||
|
yae::call_yae_dll,
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
watchdog::run_with_admin
|
||||||
])
|
])
|
||||||
.run(generate_context!())
|
.run(generate_context!())
|
||||||
.expect("error while running tauri application");
|
.expect("error while running tauri application");
|
||||||
|
|||||||
79
src-tauri/src/watchdog.rs
Normal file
79
src-tauri/src/watchdog.rs
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
//! 重启提权相关处理
|
||||||
|
//! @since Beta v0.8.7
|
||||||
|
#![cfg(target_os = "windows")]
|
||||||
|
|
||||||
|
use std::ffi::OsStr;
|
||||||
|
use std::iter::once;
|
||||||
|
use std::os::windows::ffi::OsStrExt;
|
||||||
|
use std::ptr::null_mut;
|
||||||
|
use std::time::Duration;
|
||||||
|
use tauri::AppHandle;
|
||||||
|
use windows_sys::Win32::Foundation::{HANDLE, HWND};
|
||||||
|
use windows_sys::Win32::Storage::FileSystem::SYNCHRONIZE;
|
||||||
|
use windows_sys::Win32::System::Threading::{OpenProcess, WaitForSingleObject, INFINITE};
|
||||||
|
use windows_sys::Win32::UI::Shell::ShellExecuteW;
|
||||||
|
use windows_sys::Win32::UI::WindowsAndMessaging::SW_SHOWNORMAL;
|
||||||
|
|
||||||
|
// 带参数启动
|
||||||
|
fn shell_runas_with_args(args: &str) -> Result<(), String> {
|
||||||
|
fn to_wide(s: &OsStr) -> Vec<u16> {
|
||||||
|
s.encode_wide().chain(once(0)).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
let exe_path = std::env::current_exe().map_err(|e| e.to_string())?;
|
||||||
|
let exe_wide = to_wide(exe_path.as_os_str());
|
||||||
|
let args_wide = to_wide(OsStr::new(args));
|
||||||
|
let cwd_wide =
|
||||||
|
exe_path.parent().map(|p| to_wide(p.as_os_str())).unwrap_or_else(|| to_wide(OsStr::new("")));
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let result = ShellExecuteW(
|
||||||
|
0 as HWND,
|
||||||
|
to_wide(OsStr::new("runas")).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("Failed to 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 == std::ptr::null_mut() {
|
||||||
|
// 如果拿不到句柄,可能父进程已退出,稍作等待后继续
|
||||||
|
std::thread::sleep(Duration::from_millis(300));
|
||||||
|
} else {
|
||||||
|
unsafe {
|
||||||
|
WaitForSingleObject(handle, INFINITE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 父进程已退出 → 触发 UAC 提权启动新实例
|
||||||
|
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))
|
||||||
|
// 看门狗不加载单例插件(通过参数决定 main 的初始化)
|
||||||
|
.spawn()
|
||||||
|
.map_err(|e| format!("spawn watchdog failed: {e}"))?;
|
||||||
|
|
||||||
|
// 立即退出:单例锁释放
|
||||||
|
app_handle.exit(0);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user