mirror of
https://github.com/weyne85/rustdesk.git
synced 2025-10-29 17:00:05 +00:00
working on windows service install/uninstall
This commit is contained in:
@@ -127,9 +127,6 @@ pub fn core_main() -> Option<Vec<String>> {
|
||||
log::error!("Failed to before-uninstall: {}", err);
|
||||
}
|
||||
return None;
|
||||
} else if args[0] == "--update" {
|
||||
hbb_common::allow_err!(platform::update_me());
|
||||
return None;
|
||||
} else if args[0] == "--reinstall" {
|
||||
hbb_common::allow_err!(platform::uninstall_me(false));
|
||||
hbb_common::allow_err!(platform::install_me(
|
||||
|
||||
@@ -40,8 +40,6 @@ use common::*;
|
||||
pub mod cli;
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios", feature = "cli")))]
|
||||
pub mod core_main;
|
||||
#[cfg(all(windows, feature = "hbbs"))]
|
||||
mod hbbs;
|
||||
mod lang;
|
||||
#[cfg(windows)]
|
||||
mod license;
|
||||
|
||||
@@ -722,7 +722,7 @@ pub fn is_share_rdp() -> bool {
|
||||
}
|
||||
|
||||
pub fn set_share_rdp(enable: bool) {
|
||||
let (subkey, _, _, _, _) = get_install_info();
|
||||
let (subkey, _, _, _) = get_install_info();
|
||||
let cmd = format!(
|
||||
"reg add {} /f /v share_rdp /t REG_SZ /d \"{}\"",
|
||||
subkey,
|
||||
@@ -815,11 +815,11 @@ fn get_valid_subkey() -> String {
|
||||
return get_subkey(&app_name, false);
|
||||
}
|
||||
|
||||
pub fn get_install_info() -> (String, String, String, String, String) {
|
||||
pub fn get_install_info() -> (String, String, String, String) {
|
||||
get_install_info_with_subkey(get_valid_subkey())
|
||||
}
|
||||
|
||||
fn get_default_install_info() -> (String, String, String, String, String) {
|
||||
fn get_default_install_info() -> (String, String, String, String) {
|
||||
get_install_info_with_subkey(get_subkey(&crate::get_app_name(), false))
|
||||
}
|
||||
|
||||
@@ -841,7 +841,6 @@ fn get_default_install_path() -> String {
|
||||
}
|
||||
|
||||
pub fn check_update_broker_process() -> ResultType<()> {
|
||||
// let (_, path, _, _) = get_install_info();
|
||||
let process_exe = privacy_win_mag::INJECTED_PROCESS_EXE;
|
||||
let origin_process_exe = privacy_win_mag::ORIGIN_PROCESS_EXE;
|
||||
|
||||
@@ -876,19 +875,17 @@ pub fn check_update_broker_process() -> ResultType<()> {
|
||||
let cmds = format!(
|
||||
"
|
||||
chcp 65001
|
||||
taskkill /F /IM {broker_exe}
|
||||
taskkill /F /IM {process_exe}
|
||||
copy /Y \"{origin_process_exe}\" \"{cur_exe}\"
|
||||
",
|
||||
broker_exe = process_exe,
|
||||
origin_process_exe = origin_process_exe,
|
||||
cur_exe = cur_exe.to_string_lossy().to_string(),
|
||||
cur_exe = cur_exe.to_string_lossy(),
|
||||
);
|
||||
run_cmds(cmds, false, "update_broker")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_install_info_with_subkey(subkey: String) -> (String, String, String, String, String) {
|
||||
fn get_install_info_with_subkey(subkey: String) -> (String, String, String, String) {
|
||||
let mut path = get_reg_of(&subkey, "InstallLocation");
|
||||
if path.is_empty() {
|
||||
path = get_default_install_path();
|
||||
@@ -899,8 +896,7 @@ fn get_install_info_with_subkey(subkey: String) -> (String, String, String, Stri
|
||||
crate::get_app_name()
|
||||
);
|
||||
let exe = format!("{}\\{}.exe", path, crate::get_app_name());
|
||||
let dll = format!("{}\\sciter.dll", path);
|
||||
(subkey, path, start_menu, exe, dll)
|
||||
(subkey, path, start_menu, exe)
|
||||
}
|
||||
|
||||
pub fn copy_raw_cmd(src_raw: &str, _raw: &str, _path: &str) -> String {
|
||||
@@ -923,15 +919,14 @@ pub fn copy_exe_cmd(src_exe: &str, exe: &str, path: &str) -> String {
|
||||
{main_exe}
|
||||
copy /Y \"{ORIGIN_PROCESS_EXE}\" \"{path}\\{broker_exe}\"
|
||||
",
|
||||
main_exe = main_exe,
|
||||
path = path,
|
||||
ORIGIN_PROCESS_EXE = privacy_win_mag::ORIGIN_PROCESS_EXE,
|
||||
broker_exe = privacy_win_mag::INJECTED_PROCESS_EXE,
|
||||
)
|
||||
}
|
||||
|
||||
/* // update_me has bad compatibility, so disable it.
|
||||
pub fn update_me() -> ResultType<()> {
|
||||
let (_, path, _, exe, _dll) = get_install_info();
|
||||
let (_, path, _, exe) = get_install_info();
|
||||
let src_exe = std::env::current_exe()?.to_str().unwrap_or("").to_owned();
|
||||
let cmds = format!(
|
||||
"
|
||||
@@ -949,16 +944,14 @@ pub fn update_me() -> ResultType<()> {
|
||||
lic = register_licence(),
|
||||
cur_pid = get_current_pid(),
|
||||
);
|
||||
std::thread::sleep(std::time::Duration::from_millis(1000));
|
||||
run_cmds(cmds, false, "update")?;
|
||||
std::thread::sleep(std::time::Duration::from_millis(2000));
|
||||
std::process::Command::new(&exe).arg("--tray").spawn().ok();
|
||||
std::process::Command::new(&exe).spawn().ok();
|
||||
run_after_run_cmds(false)?;
|
||||
std::process::Command::new(&exe)
|
||||
.args(&["--remove", &src_exe])
|
||||
.spawn()?;
|
||||
Ok(())
|
||||
}
|
||||
*/
|
||||
|
||||
fn get_after_install(exe: &str) -> String {
|
||||
let app_name = crate::get_app_name();
|
||||
@@ -986,24 +979,21 @@ fn get_after_install(exe: &str) -> String {
|
||||
reg add HKEY_CLASSES_ROOT\\{ext}\\shell\\open /f
|
||||
reg add HKEY_CLASSES_ROOT\\{ext}\\shell\\open\\command /f
|
||||
reg add HKEY_CLASSES_ROOT\\{ext}\\shell\\open\\command /f /ve /t REG_SZ /d \"\\\"{exe}\\\" \\\"%%1\\\"\"
|
||||
sc create {app_name} binpath= \"\\\"{exe}\\\" --service\" start= auto DisplayName= \"{app_name} Service\"
|
||||
netsh advfirewall firewall add rule name=\"{app_name} Service\" dir=in action=allow program=\"{exe}\" enable=yes
|
||||
sc start {app_name}
|
||||
{create_service}
|
||||
reg add HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System /f /v SoftwareSASGeneration /t REG_DWORD /d 1
|
||||
", ext=ext, exe=exe, app_name=app_name)
|
||||
", create_service=get_create_service(&exe))
|
||||
}
|
||||
|
||||
pub fn install_me(options: &str, path: String, silent: bool, debug: bool) -> ResultType<()> {
|
||||
let uninstall_str = get_uninstall(false);
|
||||
let mut path = path.trim_end_matches('\\').to_owned();
|
||||
let (subkey, _path, start_menu, exe, dll) = get_default_install_info();
|
||||
let (subkey, _path, start_menu, exe) = get_default_install_info();
|
||||
let mut exe = exe;
|
||||
let mut _dll = dll;
|
||||
if path.is_empty() {
|
||||
path = _path;
|
||||
} else {
|
||||
exe = exe.replace(&_path, &path);
|
||||
_dll = _dll.replace(&_path, &path);
|
||||
}
|
||||
let mut version_major = "0";
|
||||
let mut version_minor = "0";
|
||||
@@ -1018,6 +1008,7 @@ pub fn install_me(options: &str, path: String, silent: bool, debug: bool) -> Res
|
||||
if versions.len() > 2 {
|
||||
version_build = versions[2];
|
||||
}
|
||||
let app_name = crate::get_app_name();
|
||||
|
||||
let tmp_path = std::env::temp_dir().to_string_lossy().to_string();
|
||||
let mk_shortcut = write_cmds(
|
||||
@@ -1029,10 +1020,7 @@ sLinkFile = \"{tmp_path}\\{app_name}.lnk\"
|
||||
Set oLink = oWS.CreateShortcut(sLinkFile)
|
||||
oLink.TargetPath = \"{exe}\"
|
||||
oLink.Save
|
||||
",
|
||||
tmp_path = tmp_path,
|
||||
app_name = crate::get_app_name(),
|
||||
exe = exe,
|
||||
"
|
||||
),
|
||||
"vbs",
|
||||
"mk_shortcut",
|
||||
@@ -1051,10 +1039,7 @@ Set oLink = oWS.CreateShortcut(sLinkFile)
|
||||
oLink.Arguments = \"--uninstall\"
|
||||
oLink.IconLocation = \"msiexec.exe\"
|
||||
oLink.Save
|
||||
",
|
||||
tmp_path = tmp_path,
|
||||
app_name = crate::get_app_name(),
|
||||
exe = exe,
|
||||
"
|
||||
),
|
||||
"vbs",
|
||||
"uninstall_shortcut",
|
||||
@@ -1062,27 +1047,7 @@ oLink.Save
|
||||
.to_str()
|
||||
.unwrap_or("")
|
||||
.to_owned();
|
||||
let tray_shortcut = write_cmds(
|
||||
format!(
|
||||
"
|
||||
Set oWS = WScript.CreateObject(\"WScript.Shell\")
|
||||
sLinkFile = \"{tmp_path}\\{app_name} Tray.lnk\"
|
||||
|
||||
Set oLink = oWS.CreateShortcut(sLinkFile)
|
||||
oLink.TargetPath = \"{exe}\"
|
||||
oLink.Arguments = \"--tray\"
|
||||
oLink.Save
|
||||
",
|
||||
tmp_path = tmp_path,
|
||||
app_name = crate::get_app_name(),
|
||||
exe = exe,
|
||||
),
|
||||
"vbs",
|
||||
"tray_shortcut",
|
||||
)?
|
||||
.to_str()
|
||||
.unwrap_or("")
|
||||
.to_owned();
|
||||
let tray_shortcut = get_tray_shortcut(&exe, &tmp_path)?;
|
||||
let mut shortcuts = Default::default();
|
||||
if options.contains("desktopicon") {
|
||||
shortcuts = format!(
|
||||
@@ -1093,15 +1058,11 @@ oLink.Save
|
||||
}
|
||||
if options.contains("startmenu") {
|
||||
shortcuts = format!(
|
||||
"{}
|
||||
"{shortcuts}
|
||||
md \"{start_menu}\"
|
||||
copy /Y \"{tmp_path}\\{app_name}.lnk\" \"{start_menu}\\\"
|
||||
copy /Y \"{tmp_path}\\Uninstall {app_name}.lnk\" \"{start_menu}\\\"
|
||||
",
|
||||
shortcuts,
|
||||
start_menu = start_menu,
|
||||
tmp_path = tmp_path,
|
||||
app_name = crate::get_app_name(),
|
||||
"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1119,12 +1080,7 @@ if exist \"{tray_shortcut}\" del /f /q \"{tray_shortcut}\"
|
||||
if exist \"{tmp_path}\\{app_name}.lnk\" del /f /q \"{tmp_path}\\{app_name}.lnk\"
|
||||
if exist \"{tmp_path}\\Uninstall {app_name}.lnk\" del /f /q \"{tmp_path}\\Uninstall {app_name}.lnk\"
|
||||
if exist \"{tmp_path}\\{app_name} Tray.lnk\" del /f /q \"{tmp_path}\\{app_name} Tray.lnk\"
|
||||
",
|
||||
mk_shortcut = mk_shortcut,
|
||||
uninstall_shortcut = uninstall_shortcut,
|
||||
tray_shortcut = tray_shortcut,
|
||||
tmp_path = tmp_path,
|
||||
app_name = crate::get_app_name(),
|
||||
"
|
||||
);
|
||||
let src_exe = std::env::current_exe()?.to_str().unwrap_or("").to_string();
|
||||
|
||||
@@ -1145,11 +1101,12 @@ reg add {subkey} /f /v DisplayIcon /t REG_SZ /d \"{exe}\"
|
||||
reg add {subkey} /f /v DisplayName /t REG_SZ /d \"{app_name}\"
|
||||
reg add {subkey} /f /v DisplayVersion /t REG_SZ /d \"{version}\"
|
||||
reg add {subkey} /f /v Version /t REG_SZ /d \"{version}\"
|
||||
reg add {subkey} /f /v BuildDate /t REG_SZ /d \"{build_date}\"
|
||||
reg add {subkey} /f /v InstallLocation /t REG_SZ /d \"{path}\"
|
||||
reg add {subkey} /f /v Publisher /t REG_SZ /d \"{app_name}\"
|
||||
reg add {subkey} /f /v VersionMajor /t REG_DWORD /d {major}
|
||||
reg add {subkey} /f /v VersionMinor /t REG_DWORD /d {minor}
|
||||
reg add {subkey} /f /v VersionBuild /t REG_DWORD /d {build}
|
||||
reg add {subkey} /f /v VersionMajor /t REG_DWORD /d {version_major}
|
||||
reg add {subkey} /f /v VersionMinor /t REG_DWORD /d {version_minor}
|
||||
reg add {subkey} /f /v VersionBuild /t REG_DWORD /d {version_build}
|
||||
reg add {subkey} /f /v UninstallString /t REG_SZ /d \"\\\"{exe}\\\" --uninstall\"
|
||||
reg add {subkey} /f /v EstimatedSize /t REG_DWORD /d {size}
|
||||
reg add {subkey} /f /v WindowsInstaller /t REG_DWORD /d 0
|
||||
@@ -1161,32 +1118,14 @@ copy /Y \"{tmp_path}\\{app_name} Tray.lnk\" \"%PROGRAMDATA%\\Microsoft\\Windows\
|
||||
{shortcuts}
|
||||
copy /Y \"{tmp_path}\\Uninstall {app_name}.lnk\" \"{path}\\\"
|
||||
{dels}
|
||||
sc create {app_name} binpath= \"\\\"{exe}\\\" --import-config \\\"{config_path}\\\"\" start= auto DisplayName= \"{app_name} Service\"
|
||||
sc start {app_name}
|
||||
sc stop {app_name}
|
||||
sc delete {app_name}
|
||||
{import_config}
|
||||
{install_cert}
|
||||
{after_install}
|
||||
{sleep}
|
||||
",
|
||||
uninstall_str=uninstall_str,
|
||||
path=path,
|
||||
exe=exe,
|
||||
subkey=subkey,
|
||||
app_name=crate::get_app_name(),
|
||||
version=crate::VERSION,
|
||||
major=version_major,
|
||||
minor=version_minor,
|
||||
build=version_build,
|
||||
size=size,
|
||||
mk_shortcut=mk_shortcut,
|
||||
uninstall_shortcut=uninstall_shortcut,
|
||||
tray_shortcut=tray_shortcut,
|
||||
tmp_path=tmp_path,
|
||||
shortcuts=shortcuts,
|
||||
config_path=Config::file().to_str().unwrap_or(""),
|
||||
build_date=crate::BUILD_DATE,
|
||||
lic=register_licence(),
|
||||
install_cert=install_cert,
|
||||
after_install=get_after_install(&exe),
|
||||
sleep=if debug {
|
||||
"timeout 300"
|
||||
@@ -1199,19 +1138,15 @@ sc delete {app_name}
|
||||
&dels
|
||||
},
|
||||
copy_exe = copy_exe_cmd(&src_exe, &exe, &path),
|
||||
import_config = get_import_config(&exe),
|
||||
);
|
||||
run_cmds(cmds, debug, "install")?;
|
||||
std::thread::sleep(std::time::Duration::from_millis(2000));
|
||||
if !silent {
|
||||
std::process::Command::new(&exe).spawn()?;
|
||||
std::process::Command::new(&exe).arg("--tray").spawn()?;
|
||||
std::thread::sleep(std::time::Duration::from_millis(1000));
|
||||
}
|
||||
run_after_run_cmds(silent)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn run_after_install() -> ResultType<()> {
|
||||
let (_, _, _, exe, _) = get_install_info();
|
||||
let (_, _, _, exe) = get_install_info();
|
||||
run_cmds(get_after_install(&exe), true, "after_install")
|
||||
}
|
||||
|
||||
@@ -1235,12 +1170,10 @@ fn get_before_uninstall(kill_self: bool) -> String {
|
||||
taskkill /F /IM {broker_exe}
|
||||
taskkill /F /IM {app_name}.exe{filter}
|
||||
reg delete HKEY_CLASSES_ROOT\\.{ext} /f
|
||||
reg delete HKEY_CLASSES_ROOT\\{ext} /f
|
||||
netsh advfirewall firewall delete rule name=\"{app_name} Service\"
|
||||
",
|
||||
app_name = app_name,
|
||||
broker_exe = WIN_MAG_INJECTED_PROCESS_EXE,
|
||||
ext = ext,
|
||||
filter = filter,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1251,8 +1184,7 @@ fn get_uninstall(kill_self: bool) -> String {
|
||||
uninstall_cert_cmd = format!("\"{}\" --uninstall-cert", exe_path);
|
||||
}
|
||||
}
|
||||
|
||||
let (subkey, path, start_menu, _, _) = get_install_info();
|
||||
let (subkey, path, start_menu, _) = get_install_info();
|
||||
format!(
|
||||
"
|
||||
{before_uninstall}
|
||||
@@ -1264,11 +1196,7 @@ fn get_uninstall(kill_self: bool) -> String {
|
||||
if exist \"%PROGRAMDATA%\\Microsoft\\Windows\\Start Menu\\Programs\\Startup\\{app_name} Tray.lnk\" del /f /q \"%PROGRAMDATA%\\Microsoft\\Windows\\Start Menu\\Programs\\Startup\\{app_name} Tray.lnk\"
|
||||
",
|
||||
before_uninstall=get_before_uninstall(kill_self),
|
||||
uninstall_cert_cmd = uninstall_cert_cmd,
|
||||
subkey=subkey,
|
||||
app_name = crate::get_app_name(),
|
||||
path = path,
|
||||
start_menu = start_menu,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1277,6 +1205,7 @@ pub fn uninstall_me(kill_self: bool) -> ResultType<()> {
|
||||
}
|
||||
|
||||
fn write_cmds(cmds: String, ext: &str, tip: &str) -> ResultType<std::path::PathBuf> {
|
||||
let mut cmds = cmds;
|
||||
let mut tmp = std::env::temp_dir();
|
||||
// When dir contains these characters, the bat file will not execute in elevated mode.
|
||||
if vec!["&", "@", "^"]
|
||||
@@ -1289,9 +1218,20 @@ fn write_cmds(cmds: String, ext: &str, tip: &str) -> ResultType<std::path::PathB
|
||||
}
|
||||
tmp.push(format!("{}_{}.{}", crate::get_app_name(), tip, ext));
|
||||
let mut file = std::fs::File::create(&tmp)?;
|
||||
if ext == "bat" {
|
||||
let tmp2 = get_undone_file(&tmp);
|
||||
std::fs::File::create(&tmp2).ok();
|
||||
cmds = format!(
|
||||
"
|
||||
{cmds}
|
||||
if exist \"{path}\" del /f /q \"{path}\"
|
||||
",
|
||||
path = tmp2.to_string_lossy()
|
||||
);
|
||||
}
|
||||
// in case cmds mixed with \r\n and \n, make sure all ending with \r\n
|
||||
// in some windows, \r\n required for cmd file to run
|
||||
let cmds = cmds.replace("\r\n", "\n").replace("\n", "\r\n");
|
||||
cmds = cmds.replace("\r\n", "\n").replace("\n", "\r\n");
|
||||
if ext == "vbs" {
|
||||
let mut v: Vec<u16> = cmds.encode_utf16().collect();
|
||||
// utf8 -> utf16le which vbs support it only
|
||||
@@ -1310,8 +1250,18 @@ fn to_le(v: &mut [u16]) -> &[u8] {
|
||||
unsafe { v.align_to().1 }
|
||||
}
|
||||
|
||||
fn get_undone_file(tmp: &PathBuf) -> PathBuf {
|
||||
let mut tmp1 = tmp.clone();
|
||||
tmp1.set_file_name(format!(
|
||||
"{}.undone",
|
||||
tmp.file_name().unwrap().to_string_lossy()
|
||||
));
|
||||
tmp1
|
||||
}
|
||||
|
||||
fn run_cmds(cmds: String, show: bool, tip: &str) -> ResultType<()> {
|
||||
let tmp = write_cmds(cmds, "bat", tip)?;
|
||||
let tmp2 = get_undone_file(&tmp);
|
||||
let tmp_fn = tmp.to_str().unwrap_or("");
|
||||
let res = runas::Command::new("cmd")
|
||||
.args(&["/C", &tmp_fn])
|
||||
@@ -1322,6 +1272,10 @@ fn run_cmds(cmds: String, show: bool, tip: &str) -> ResultType<()> {
|
||||
allow_err!(std::fs::remove_file(tmp));
|
||||
}
|
||||
let _ = res?;
|
||||
if tmp2.exists() {
|
||||
allow_err!(std::fs::remove_file(tmp2));
|
||||
bail!("{} failed", tip);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1357,7 +1311,7 @@ pub fn is_installed() -> bool {
|
||||
service::ServiceAccess,
|
||||
service_manager::{ServiceManager, ServiceManagerAccess},
|
||||
};
|
||||
let (_, _, _, exe, _) = get_install_info();
|
||||
let (_, _, _, exe) = get_install_info();
|
||||
if !std::fs::metadata(exe).is_ok() {
|
||||
return false;
|
||||
}
|
||||
@@ -1372,18 +1326,8 @@ pub fn is_installed() -> bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
pub fn get_installed_version() -> String {
|
||||
let (_, _, _, exe, _) = get_install_info();
|
||||
if let Ok(output) = std::process::Command::new(exe).arg("--version").output() {
|
||||
for line in String::from_utf8_lossy(&output.stdout).lines() {
|
||||
return line.to_owned();
|
||||
}
|
||||
}
|
||||
"".to_owned()
|
||||
}
|
||||
|
||||
fn get_reg(name: &str) -> String {
|
||||
let (subkey, _, _, _, _) = get_install_info();
|
||||
pub fn get_reg(name: &str) -> String {
|
||||
let (subkey, _, _, _) = get_install_info();
|
||||
get_reg_of(&subkey, name)
|
||||
}
|
||||
|
||||
@@ -1434,7 +1378,7 @@ pub fn bootstrap() {
|
||||
}
|
||||
|
||||
fn register_licence() -> String {
|
||||
let (subkey, _, _, _, _) = get_install_info();
|
||||
let (subkey, _, _, _) = get_install_info();
|
||||
if let Ok(lic) = get_license_from_exe_name() {
|
||||
format!(
|
||||
"
|
||||
@@ -1442,7 +1386,6 @@ fn register_licence() -> String {
|
||||
reg add {subkey} /f /v Host /t REG_SZ /d \"{host}\"
|
||||
reg add {subkey} /f /v Api /t REG_SZ /d \"{api}\"
|
||||
",
|
||||
subkey = subkey,
|
||||
key = &lic.key,
|
||||
host = &lic.host,
|
||||
api = &lic.api,
|
||||
@@ -1469,9 +1412,7 @@ Set oLink = oWS.CreateShortcut(sLinkFile)
|
||||
oLink.TargetPath = \"{exe}\"
|
||||
oLink.Arguments = \"--connect {id}\"
|
||||
oLink.Save
|
||||
",
|
||||
exe = exe,
|
||||
id = id,
|
||||
"
|
||||
),
|
||||
"vbs",
|
||||
"connect_shortcut",
|
||||
@@ -2181,6 +2122,117 @@ pub fn is_process_consent_running() -> ResultType<bool> {
|
||||
Ok(output.status.success() && !output.stdout.is_empty())
|
||||
}
|
||||
|
||||
pub fn uninstall_service(show_new_window: bool) -> ResultType<()> {
|
||||
let filter = format!(" /FI \"PID ne {}\"", get_current_pid());
|
||||
Config::set_option("stop-service".into(), "Y".into());
|
||||
let cmds = format!(
|
||||
"
|
||||
chcp 65001
|
||||
sc stop {app_name}
|
||||
sc delete {app_name}
|
||||
if exist \"%PROGRAMDATA%\\Microsoft\\Windows\\Start Menu\\Programs\\Startup\\{app_name} Tray.lnk\" del /f /q \"%PROGRAMDATA%\\Microsoft\\Windows\\Start Menu\\Programs\\Startup\\{app_name} Tray.lnk\"
|
||||
taskkill /F /IM {app_name}.exe{filter}
|
||||
",
|
||||
app_name = crate::get_app_name(),
|
||||
);
|
||||
if let Err(err) = run_cmds(cmds, false, "uninstall") {
|
||||
Config::set_option("stop-service".into(), "".into());
|
||||
bail!(err);
|
||||
}
|
||||
run_after_run_cmds(!show_new_window)?;
|
||||
std::process::exit(0);
|
||||
}
|
||||
|
||||
pub fn install_service() -> ResultType<()> {
|
||||
let (_, _, _, exe) = get_install_info();
|
||||
let tmp_path = std::env::temp_dir().to_string_lossy().to_string();
|
||||
let tray_shortcut = get_tray_shortcut(&exe, &tmp_path)?;
|
||||
let filter = format!(" /FI \"PID ne {}\"", get_current_pid());
|
||||
Config::set_option("stop-service".into(), "".into());
|
||||
let cmds = format!(
|
||||
"
|
||||
chcp 65001
|
||||
cscript \"{tray_shortcut}\"
|
||||
copy /Y \"{tmp_path}\\{app_name} Tray.lnk\" \"%PROGRAMDATA%\\Microsoft\\Windows\\Start Menu\\Programs\\Startup\\\"
|
||||
{import_config}
|
||||
{create_service}
|
||||
if exist \"{tray_shortcut}\" del /f /q \"{tray_shortcut}\"
|
||||
taskkill /F /IM {app_name}.exe{filter}
|
||||
",
|
||||
app_name = crate::get_app_name(),
|
||||
import_config = get_import_config(&exe),
|
||||
create_service = get_create_service(&exe),
|
||||
);
|
||||
if let Err(err) = run_cmds(cmds, false, "install") {
|
||||
Config::set_option("stop-service".into(), "Y".into());
|
||||
bail!(err);
|
||||
}
|
||||
run_after_run_cmds(false)?;
|
||||
std::process::exit(0);
|
||||
}
|
||||
|
||||
pub fn get_tray_shortcut(exe: &str, tmp_path: &str) -> ResultType<String> {
|
||||
Ok(write_cmds(
|
||||
format!(
|
||||
"
|
||||
Set oWS = WScript.CreateObject(\"WScript.Shell\")
|
||||
sLinkFile = \"{tmp_path}\\{app_name} Tray.lnk\"
|
||||
|
||||
Set oLink = oWS.CreateShortcut(sLinkFile)
|
||||
oLink.TargetPath = \"{exe}\"
|
||||
oLink.Arguments = \"--tray\"
|
||||
oLink.Save
|
||||
",
|
||||
app_name = crate::get_app_name(),
|
||||
),
|
||||
"vbs",
|
||||
"tray_shortcut",
|
||||
)?
|
||||
.to_str()
|
||||
.unwrap_or("")
|
||||
.to_owned())
|
||||
}
|
||||
|
||||
fn get_import_config(exe: &str) -> String {
|
||||
format!("
|
||||
sc create {app_name} binpath= \"\\\"{exe}\\\" --import-config \\\"{config_path}\\\"\" start= auto DisplayName= \"{app_name} Service\"
|
||||
sc start {app_name}
|
||||
sc stop {app_name}
|
||||
sc delete {app_name}
|
||||
",
|
||||
app_name = crate::get_app_name(),
|
||||
config_path=Config::file().to_str().unwrap_or(""),
|
||||
)
|
||||
}
|
||||
|
||||
fn get_create_service(exe: &str) -> String {
|
||||
let stop = Config::get_option("stop-service") == "Y";
|
||||
if stop {
|
||||
format!("
|
||||
if exist \"%PROGRAMDATA%\\Microsoft\\Windows\\Start Menu\\Programs\\Startup\\{app_name} Tray.lnk\" del /f /q \"%PROGRAMDATA%\\Microsoft\\Windows\\Start Menu\\Programs\\Startup\\{app_name} Tray.lnk\"
|
||||
", app_name = crate::get_app_name())
|
||||
} else {
|
||||
format!("
|
||||
sc create {app_name} binpath= \"\\\"{exe}\\\" --service\" start= auto DisplayName= \"{app_name} Service\"
|
||||
sc start {app_name}
|
||||
",
|
||||
app_name = crate::get_app_name())
|
||||
}
|
||||
}
|
||||
|
||||
fn run_after_run_cmds(silent: bool) -> ResultType<()> {
|
||||
let (_, _, _, exe) = get_install_info();
|
||||
std::thread::sleep(std::time::Duration::from_millis(2000));
|
||||
if !silent {
|
||||
std::process::Command::new(&exe).spawn()?;
|
||||
}
|
||||
if Config::get_option("stop-service") != "Y" {
|
||||
std::process::Command::new(&exe).arg("--tray").spawn()?;
|
||||
}
|
||||
std::thread::sleep(std::time::Duration::from_millis(1000));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
124
src/tray.rs
124
src/tray.rs
@@ -1,94 +1,3 @@
|
||||
#[cfg(target_os = "windows")]
|
||||
use super::ui_interface::get_option_opt;
|
||||
#[cfg(target_os = "windows")]
|
||||
use std::sync::{Arc, Mutex};
|
||||
#[cfg(target_os = "windows")]
|
||||
use trayicon::{MenuBuilder, TrayIconBuilder};
|
||||
#[cfg(target_os = "windows")]
|
||||
use winit::{
|
||||
event::Event,
|
||||
event_loop::{ControlFlow, EventLoop},
|
||||
};
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
#[derive(Clone, Eq, PartialEq, Debug)]
|
||||
enum Events {
|
||||
DoubleClickTrayIcon,
|
||||
StopService,
|
||||
StartService,
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
pub fn start_tray() {
|
||||
let event_loop = EventLoop::<Events>::with_user_event();
|
||||
let proxy = event_loop.create_proxy();
|
||||
let icon = include_bytes!("../res/tray-icon.ico");
|
||||
let mut tray_icon = TrayIconBuilder::new()
|
||||
.sender_winit(proxy)
|
||||
.icon_from_buffer(icon)
|
||||
.tooltip("RustDesk")
|
||||
.on_double_click(Events::DoubleClickTrayIcon)
|
||||
.build()
|
||||
.unwrap();
|
||||
let old_state = Arc::new(Mutex::new(0));
|
||||
let _sender = crate::ui_interface::SENDER.lock().unwrap();
|
||||
event_loop.run(move |event, _, control_flow| {
|
||||
if get_option_opt("ipc-closed").is_some() {
|
||||
*control_flow = ControlFlow::Exit;
|
||||
return;
|
||||
} else {
|
||||
*control_flow = ControlFlow::Wait;
|
||||
}
|
||||
let stopped = is_service_stopped();
|
||||
let state = if stopped { 2 } else { 1 };
|
||||
let old = *old_state.lock().unwrap();
|
||||
if state != old {
|
||||
hbb_common::log::info!("State changed");
|
||||
let mut m = MenuBuilder::new();
|
||||
if state == 2 {
|
||||
m = m.item(
|
||||
&crate::client::translate("Start Service".to_owned()),
|
||||
Events::StartService,
|
||||
);
|
||||
} else {
|
||||
m = m.item(
|
||||
&crate::client::translate("Stop service".to_owned()),
|
||||
Events::StopService,
|
||||
);
|
||||
}
|
||||
tray_icon.set_menu(&m).ok();
|
||||
*old_state.lock().unwrap() = state;
|
||||
}
|
||||
|
||||
match event {
|
||||
Event::UserEvent(e) => match e {
|
||||
Events::DoubleClickTrayIcon => {
|
||||
crate::run_me(Vec::<&str>::new()).ok();
|
||||
}
|
||||
Events::StopService => {
|
||||
crate::ipc::set_option("stop-service", "Y");
|
||||
}
|
||||
Events::StartService => {
|
||||
crate::ipc::set_option("stop-service", "");
|
||||
}
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// Check if service is stoped.
|
||||
/// Return [`true`] if service is stoped, [`false`] otherwise.
|
||||
#[inline]
|
||||
#[cfg(target_os = "windows")]
|
||||
fn is_service_stopped() -> bool {
|
||||
if let Some(v) = get_option_opt("stop-service") {
|
||||
v == "Y"
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// Start a tray icon in Linux
|
||||
///
|
||||
/// [Block]
|
||||
@@ -96,13 +5,13 @@ fn is_service_stopped() -> bool {
|
||||
#[cfg(target_os = "linux")]
|
||||
pub fn start_tray() {}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
#[cfg(any(target_os = "macos", target_os = "windows"))]
|
||||
pub fn start_tray() {
|
||||
use hbb_common::{allow_err, log};
|
||||
allow_err!(make_tray());
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
#[cfg(any(target_os = "macos", target_os = "windows"))]
|
||||
pub fn make_tray() -> hbb_common::ResultType<()> {
|
||||
// https://github.com/tauri-apps/tray-icon/blob/dev/examples/tao.rs
|
||||
use hbb_common::anyhow::Context;
|
||||
@@ -111,13 +20,21 @@ pub fn make_tray() -> hbb_common::ResultType<()> {
|
||||
menu::{Menu, MenuEvent, MenuItem},
|
||||
ClickEvent, TrayEvent, TrayIconBuilder,
|
||||
};
|
||||
let mode = dark_light::detect();
|
||||
const LIGHT: &[u8] = include_bytes!("../res/mac-tray-light-x2.png");
|
||||
const DARK: &[u8] = include_bytes!("../res/mac-tray-dark-x2.png");
|
||||
let icon = match mode {
|
||||
dark_light::Mode::Dark => LIGHT,
|
||||
_ => DARK,
|
||||
};
|
||||
let icon;
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
let mode = dark_light::detect();
|
||||
const LIGHT: &[u8] = include_bytes!("../res/mac-tray-light-x2.png");
|
||||
const DARK: &[u8] = include_bytes!("../res/mac-tray-dark-x2.png");
|
||||
icon = match mode {
|
||||
dark_light::Mode::Dark => LIGHT,
|
||||
_ => DARK,
|
||||
};
|
||||
}
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
icon = include_bytes!("../res/tray-icon.ico");
|
||||
}
|
||||
let (icon_rgba, icon_width, icon_height) = {
|
||||
let image = image::load_from_memory(icon)
|
||||
.context("Failed to open icon path")?
|
||||
@@ -153,6 +70,7 @@ pub fn make_tray() -> hbb_common::ResultType<()> {
|
||||
|
||||
event_loop.run(move |_event, _, control_flow| {
|
||||
if !docker_hiden {
|
||||
#[cfg(target_os = "macos")]
|
||||
crate::platform::macos::hide_dock();
|
||||
docker_hiden = true;
|
||||
}
|
||||
@@ -160,14 +78,20 @@ pub fn make_tray() -> hbb_common::ResultType<()> {
|
||||
|
||||
if let Ok(event) = menu_channel.try_recv() {
|
||||
if event.id == quit_i.id() {
|
||||
#[cfg(target_os = "macos")]
|
||||
crate::platform::macos::uninstall(false);
|
||||
#[cfg(any(target_os = "linux", target_os = "windows"))]
|
||||
crate::platform::uninstall_service(false).ok();
|
||||
}
|
||||
println!("{event:?}");
|
||||
}
|
||||
|
||||
if let Ok(event) = tray_channel.try_recv() {
|
||||
if event.event == ClickEvent::Double {
|
||||
#[cfg(target_os = "macos")]
|
||||
crate::platform::macos::handle_application_should_open_untitled_file();
|
||||
#[cfg(target_os = "windows")]
|
||||
crate::run_me(Vec::<&str>::new()).ok();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -74,28 +74,7 @@ pub fn install_me(_options: String, _path: String, _silent: bool, _debug: bool)
|
||||
|
||||
#[inline]
|
||||
pub fn update_me(_path: String) {
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
allow_err!(crate::platform::linux::exec_privileged(&[
|
||||
"apt", "install", "-f", &_path
|
||||
]));
|
||||
allow_err!(std::fs::remove_file(&_path));
|
||||
allow_err!(crate::run_me(Vec::<&str>::new()));
|
||||
}
|
||||
#[cfg(windows)]
|
||||
{
|
||||
let mut path = _path;
|
||||
if path.is_empty() {
|
||||
if let Ok(tmp) = std::env::current_exe() {
|
||||
path = tmp.to_string_lossy().to_string();
|
||||
}
|
||||
}
|
||||
std::process::Command::new(path)
|
||||
.arg("--update")
|
||||
.spawn()
|
||||
.ok();
|
||||
std::process::exit(0);
|
||||
}
|
||||
goto_install();
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@@ -296,11 +275,24 @@ pub fn set_options(m: HashMap<String, String>) {
|
||||
#[inline]
|
||||
pub fn set_option(key: String, value: String) {
|
||||
let mut options = OPTIONS.lock().unwrap();
|
||||
#[cfg(target_os = "macos")]
|
||||
if &key == "stop-service" {
|
||||
let is_stop = value == "Y";
|
||||
if is_stop && crate::platform::macos::uninstall(true) {
|
||||
return;
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
let is_stop = value == "Y";
|
||||
if is_stop && crate::platform::macos::uninstall(true) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
#[cfg(any(target_os = "windows"))]
|
||||
{
|
||||
if crate::platform::is_installed() {
|
||||
if value == "Y" {
|
||||
crate::platform::install_service().ok();
|
||||
} else {
|
||||
crate::platform::uninstall_service(true).ok();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if value.is_empty() {
|
||||
@@ -396,10 +388,8 @@ pub fn is_installed_lower_version() -> bool {
|
||||
return false;
|
||||
#[cfg(windows)]
|
||||
{
|
||||
let installed_version = crate::platform::windows::get_installed_version();
|
||||
let a = hbb_common::get_version_number(crate::VERSION);
|
||||
let b = hbb_common::get_version_number(&installed_version);
|
||||
return a > b;
|
||||
let b = crate::platform::windows::get_reg("BuildDate");
|
||||
return crate::BUILD_DATE.cmp(&b).is_gt();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user