From f4c40d733e74879c122155fe4980798b2f3a0523 Mon Sep 17 00:00:00 2001 From: fufesou <13586388+fufesou@users.noreply.github.com> Date: Thu, 8 Aug 2024 22:07:06 +0800 Subject: [PATCH] Fix/exe upgrade options (#9001) * fix: exe upgrade, use previous options Signed-off-by: fufesou * refact: msi, shortcuts options, swap pos Signed-off-by: fufesou --------- Signed-off-by: fufesou --- flutter/lib/desktop/pages/install_page.dart | 6 ++ res/msi/Package/UI/MyInstallDirDlg.wxs | 4 +- src/flutter_ffi.rs | 4 ++ src/platform/windows.rs | 73 ++++++++++++++++++--- src/ui.rs | 5 ++ src/ui/install.tis | 7 +- src/ui_interface.rs | 8 +++ 7 files changed, 94 insertions(+), 13 deletions(-) diff --git a/flutter/lib/desktop/pages/install_page.dart b/flutter/lib/desktop/pages/install_page.dart index a860fe89e..5285fc35f 100644 --- a/flutter/lib/desktop/pages/install_page.dart +++ b/flutter/lib/desktop/pages/install_page.dart @@ -1,3 +1,5 @@ +import 'dart:convert'; + import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; import 'package:flutter_hbb/common.dart'; @@ -73,6 +75,9 @@ class _InstallPageBodyState extends State<_InstallPageBody> _InstallPageBodyState() { controller = TextEditingController(text: bind.installInstallPath()); + final installOptions = jsonDecode(bind.installInstallOptions()); + startmenu.value = installOptions['STARTMENUSHORTCUTS'] != '0'; + desktopicon.value = installOptions['DESKTOPSHORTCUTS'] != '0'; } @override @@ -249,6 +254,7 @@ class _InstallPageBodyState extends State<_InstallPageBody> if (desktopicon.value) args += ' desktopicon'; bind.installInstallMe(options: args, path: controller.text); } + do_install(); } diff --git a/res/msi/Package/UI/MyInstallDirDlg.wxs b/res/msi/Package/UI/MyInstallDirDlg.wxs index 7c554a121..6e27e2b28 100644 --- a/res/msi/Package/UI/MyInstallDirDlg.wxs +++ b/res/msi/Package/UI/MyInstallDirDlg.wxs @@ -23,8 +23,8 @@ - - + + diff --git a/src/flutter_ffi.rs b/src/flutter_ffi.rs index 46261a37e..7fb324b3f 100644 --- a/src/flutter_ffi.rs +++ b/src/flutter_ffi.rs @@ -1849,6 +1849,10 @@ pub fn install_install_path() -> SyncReturn { SyncReturn(install_path()) } +pub fn install_install_options() -> SyncReturn { + SyncReturn(install_options()) +} + pub fn main_account_auth(op: String, remember_me: bool) { let id = get_id(); let uuid = get_uuid(); diff --git a/src/platform/windows.rs b/src/platform/windows.rs index 09ff347a2..51aee97a3 100644 --- a/src/platform/windows.rs +++ b/src/platform/windows.rs @@ -1,21 +1,20 @@ use super::{CursorData, ResultType}; -use crate::common::PORTABLE_APPNAME_RUNTIME_ENV_KEY; use crate::{ + common::PORTABLE_APPNAME_RUNTIME_ENV_KEY, custom_server::*, ipc, privacy_mode::win_topmost_window::{self, WIN_TOPMOST_INJECTED_PROCESS_EXE}, }; -use hbb_common::libc::{c_int, wchar_t}; use hbb_common::{ allow_err, anyhow::anyhow, bail, config::{self, Config}, + libc::{c_int, wchar_t}, log, message_proto::{DisplayInfo, Resolution, WindowsSession}, sleep, timeout, tokio, }; -use std::process::{Command, Stdio}; use std::{ collections::HashMap, ffi::{CString, OsString}, @@ -24,15 +23,16 @@ use std::{ mem, os::windows::process::CommandExt, path::*, + process::{Command, Stdio}, ptr::null_mut, sync::{atomic::Ordering, Arc, Mutex}, time::{Duration, Instant}, }; use wallpaper; -use winapi::um::sysinfoapi::{GetNativeSystemInfo, SYSTEM_INFO}; use winapi::{ ctypes::c_void, shared::{minwindef::*, ntdef::NULL, windef::*, winerror::*}, + um::sysinfoapi::{GetNativeSystemInfo, SYSTEM_INFO}, um::{ errhandlingapi::GetLastError, handleapi::CloseHandle, @@ -63,13 +63,15 @@ use windows_service::{ }, service_control_handler::{self, ServiceControlHandlerResult}, }; -use winreg::enums::*; -use winreg::RegKey; +use winreg::{enums::*, RegKey}; pub const FLUTTER_RUNNER_WIN32_WINDOW_CLASS: &'static str = "FLUTTER_RUNNER_WIN32_WINDOW"; // main window, install window pub const EXPLORER_EXE: &'static str = "explorer.exe"; pub const SET_FOREGROUND_WINDOW: &'static str = "SET_FOREGROUND_WINDOW"; +const REG_NAME_INSTALL_DESKTOPSHORTCUTS: &str = "DESKTOPSHORTCUTS"; +const REG_NAME_INSTALL_STARTMENUSHORTCUTS: &str = "STARTMENUSHORTCUTS"; + pub fn get_focused_display(displays: Vec) -> Option { unsafe { let hwnd = GetForegroundWindow(); @@ -992,6 +994,32 @@ fn get_valid_subkey() -> String { return get_subkey(&app_name, false); } +// Return install options other than InstallLocation. +pub fn get_install_options() -> String { + let app_name = crate::get_app_name(); + let subkey = format!(".{}", app_name.to_lowercase()); + let mut opts = HashMap::new(); + + let desktop_shortcuts = get_reg_of_hkcr(&subkey, REG_NAME_INSTALL_DESKTOPSHORTCUTS); + if let Some(desktop_shortcuts) = desktop_shortcuts { + opts.insert(REG_NAME_INSTALL_DESKTOPSHORTCUTS, desktop_shortcuts); + } + let start_menu_shortcuts = get_reg_of_hkcr(&subkey, REG_NAME_INSTALL_STARTMENUSHORTCUTS); + if let Some(start_menu_shortcuts) = start_menu_shortcuts { + opts.insert(REG_NAME_INSTALL_STARTMENUSHORTCUTS, start_menu_shortcuts); + } + serde_json::to_string(&opts).unwrap_or("{}".to_owned()) +} + +// This function return Option, because some registry value may be empty. +fn get_reg_of_hkcr(subkey: &str, name: &str) -> Option { + let hkcr = RegKey::predef(HKEY_CLASSES_ROOT); + if let Ok(tmp) = hkcr.open_subkey(subkey.replace("HKEY_CLASSES_ROOT\\", "")) { + return tmp.get_value(name).ok(); + } + None +} + pub fn get_install_info() -> (String, String, String, String) { get_install_info_with_subkey(get_valid_subkey()) } @@ -1101,7 +1129,11 @@ pub fn copy_exe_cmd(src_exe: &str, exe: &str, path: &str) -> ResultType )) } -fn get_after_install(exe: &str) -> String { +fn get_after_install( + exe: &str, + reg_value_start_menu_shortcuts: Option, + reg_value_desktop_shortcuts: Option, +) -> String { let app_name = crate::get_app_name(); let ext = app_name.to_lowercase(); @@ -1112,9 +1144,24 @@ fn get_after_install(exe: &str) -> String { hcu.delete_subkey_all(format!("Software\\Classes\\{}", exe)) .ok(); + let desktop_shortcuts = reg_value_desktop_shortcuts + .map(|v| { + format!("reg add HKEY_CLASSES_ROOT\\.{ext} /f /v {REG_NAME_INSTALL_DESKTOPSHORTCUTS} /t REG_SZ /d \"{v}\"") + }) + .unwrap_or_default(); + let start_menu_shortcuts = reg_value_start_menu_shortcuts + .map(|v| { + format!( + "reg add HKEY_CLASSES_ROOT\\.{ext} /f /v {REG_NAME_INSTALL_STARTMENUSHORTCUTS} /t REG_SZ /d \"{v}\"" + ) + }) + .unwrap_or_default(); + format!(" chcp 65001 reg add HKEY_CLASSES_ROOT\\.{ext} /f + {desktop_shortcuts} + {start_menu_shortcuts} reg add HKEY_CLASSES_ROOT\\.{ext}\\DefaultIcon /f reg add HKEY_CLASSES_ROOT\\.{ext}\\DefaultIcon /f /ve /t REG_SZ /d \"\\\"{exe}\\\",0\" reg add HKEY_CLASSES_ROOT\\.{ext}\\shell /f @@ -1197,6 +1244,8 @@ oLink.Save .unwrap_or("") .to_owned(); let tray_shortcut = get_tray_shortcut(&exe, &tmp_path)?; + let mut reg_value_desktop_shortcuts = "0".to_owned(); + let mut reg_value_start_menu_shortcuts = "0".to_owned(); let mut shortcuts = Default::default(); if options.contains("desktopicon") { shortcuts = format!( @@ -1204,6 +1253,7 @@ oLink.Save tmp_path, crate::get_app_name() ); + reg_value_desktop_shortcuts = "1".to_owned(); } if options.contains("startmenu") { shortcuts = format!( @@ -1213,6 +1263,7 @@ copy /Y \"{tmp_path}\\{app_name}.lnk\" \"{start_menu}\\\" copy /Y \"{tmp_path}\\Uninstall {app_name}.lnk\" \"{start_menu}\\\" " ); + reg_value_start_menu_shortcuts = "1".to_owned(); } let meta = std::fs::symlink_metadata(std::env::current_exe()?)?; @@ -1281,7 +1332,11 @@ copy /Y \"{tmp_path}\\Uninstall {app_name}.lnk\" \"{path}\\\" ", version = crate::VERSION.replace("-", "."), build_date = crate::BUILD_DATE, - after_install = get_after_install(&exe), + after_install = get_after_install( + &exe, + Some(reg_value_start_menu_shortcuts), + Some(reg_value_desktop_shortcuts) + ), sleep = if debug { "timeout 300" } else { "" }, dels = if debug { "" } else { &dels }, copy_exe = copy_exe_cmd(&src_exe, &exe, &path)?, @@ -1294,7 +1349,7 @@ copy /Y \"{tmp_path}\\Uninstall {app_name}.lnk\" \"{path}\\\" pub fn run_after_install() -> ResultType<()> { let (_, _, _, exe) = get_install_info(); - run_cmds(get_after_install(&exe), true, "after_install") + run_cmds(get_after_install(&exe, None, None), true, "after_install") } pub fn run_before_uninstall() -> ResultType<()> { diff --git a/src/ui.rs b/src/ui.rs index aa36fc578..d3d291433 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -312,6 +312,10 @@ impl UI { install_path() } + fn install_options(&self) -> String { + install_options() + } + fn get_socks(&self) -> Value { Value::from_iter(get_socks()) } @@ -683,6 +687,7 @@ impl sciter::EventHandler for UI { fn set_share_rdp(bool); fn is_installed_lower_version(); fn install_path(); + fn install_options(); fn goto_install(); fn is_process_trusted(bool); fn is_can_screen_recording(bool); diff --git a/src/ui/install.tis b/src/ui/install.tis index 3a7920bcf..fad407123 100644 --- a/src/ui/install.tis +++ b/src/ui/install.tis @@ -6,13 +6,16 @@ var install_path = ""; class Install: Reactor.Component { function render() { + const install_options = JSON.parse(view.install_options()); + const desktop_icon = { checked: install_options?.DESKTOPSHORTCUTS == '0' ? false : true }; + const startmenu_shortcuts = { checked: install_options?.STARTMENUSHORTCUTS == '0' ? false : true }; return
{translate('Installation')}
{translate('Installation Path')} {": "}
-
{translate('Create start menu shortcuts')}
-
{translate('Create desktop icon')}
+
{translate('Create start menu shortcuts')}
+
{translate('Create desktop icon')}
{translate('End-user license agreement')}
{translate('agreement_tip')}
diff --git a/src/ui_interface.rs b/src/ui_interface.rs index e32fcb49d..c39a58068 100644 --- a/src/ui_interface.rs +++ b/src/ui_interface.rs @@ -426,6 +426,14 @@ pub fn install_path() -> String { return "".to_owned(); } +#[inline] +pub fn install_options() -> String { + #[cfg(windows)] + return crate::platform::windows::get_install_options(); + #[cfg(not(windows))] + return "{}".to_owned(); +} + #[inline] pub fn get_socks() -> Vec { #[cfg(not(any(target_os = "android", target_os = "ios")))]