From 279fb72a4fa970192cbe0d514a7c1228453b6709 Mon Sep 17 00:00:00 2001 From: fufesou <13586388+fufesou@users.noreply.github.com> Date: Thu, 24 Apr 2025 18:24:22 +0800 Subject: [PATCH] fix: remote printer, update install option (#11461) * fix: remote printer, update install option Signed-off-by: fufesou * Add comments Signed-off-by: fufesou * Add comments Signed-off-by: fufesou * Win, run_cmds, remove extra whitespace and newline Signed-off-by: fufesou --------- Signed-off-by: fufesou --- .../desktop/pages/desktop_setting_page.dart | 6 ++-- src/flutter_ffi.rs | 10 ++++++ src/ipc.rs | 28 +++++++++++++++++ src/platform/windows.rs | 31 ++++++++++++++++++- src/server.rs | 2 ++ 5 files changed, 73 insertions(+), 4 deletions(-) diff --git a/flutter/lib/desktop/pages/desktop_setting_page.dart b/flutter/lib/desktop/pages/desktop_setting_page.dart index d21e7d347..9870437e4 100644 --- a/flutter/lib/desktop/pages/desktop_setting_page.dart +++ b/flutter/lib/desktop/pages/desktop_setting_page.dart @@ -1979,7 +1979,7 @@ class __PrinterState extends State<_Printer> { final installed = bind.mainIsInstalled(); // `is-printer-installed` may fail, but it's rare case. // Add additional error message here if it's really needed. - final driver_installed = + final isPrinterInstalled = bind.mainGetCommonSync(key: 'is-printer-installed') == 'true'; final List children = []; @@ -1988,8 +1988,8 @@ class __PrinterState extends State<_Printer> { } else { children.addAll([ if (!installed) tipClientNotInstalled(), - if (installed && !driver_installed) tipPrinterNotInstalled(), - if (installed && driver_installed) tipReady() + if (installed && !isPrinterInstalled) tipPrinterNotInstalled(), + if (installed && isPrinterInstalled) tipReady() ]); } return _Card(title: 'Outgoing Print Jobs', children: children); diff --git a/src/flutter_ffi.rs b/src/flutter_ffi.rs index 84b39dc85..c446e6a83 100644 --- a/src/flutter_ffi.rs +++ b/src/flutter_ffi.rs @@ -2438,6 +2438,16 @@ pub fn main_set_common(_key: String, _value: String) { (false, err) } }; + if success { + // Use `ipc` to notify the server process to update the install option in the registry. + // Because `install_update_printer()` may prompt for permissions, there is no need to prompt again here. + if let Err(e) = crate::ipc::set_install_option( + crate::platform::REG_NAME_INSTALL_PRINTER.to_string(), + "1".to_string(), + ) { + log::error!("Failed to set install printer option: {}", e); + } + } let data = HashMap::from([ ("name", serde_json::json!("install-printer-res")), ("success", serde_json::json!(success)), diff --git a/src/ipc.rs b/src/ipc.rs index 07b011740..4ddceca27 100644 --- a/src/ipc.rs +++ b/src/ipc.rs @@ -274,6 +274,7 @@ pub enum Data { ClearTrustedDevices, #[cfg(all(target_os = "windows", feature = "flutter"))] PrinterData(Vec), + InstallOption(Option<(String, String)>), } #[tokio::main(flavor = "current_thread")] @@ -662,6 +663,23 @@ async fn handle(data: Data, stream: &mut Connection) { Data::ClearTrustedDevices => { Config::clear_trusted_devices(); } + Data::InstallOption(opt) => match opt { + Some((_k, _v)) => { + #[cfg(target_os = "windows")] + if let Err(e) = crate::platform::windows::update_install_option(&_k, &_v) { + log::error!( + "Failed to update install option \"{}\" to \"{}\", error: {}", + &_k, + &_v, + e + ); + } + } + None => { + // `None` is usually used to get values. + // This branch is left blank for unification and further use. + } + }, _ => {} } } @@ -1277,6 +1295,16 @@ async fn handle_wayland_screencast_restore_token( return Ok(None); } +#[tokio::main(flavor = "current_thread")] +pub async fn set_install_option(k: String, v: String) -> ResultType<()> { + if let Ok(mut c) = connect(1000, "").await { + c.send(&&Data::InstallOption(Some((k, v)))).await?; + // do not put below before connect, because we need to check should_exit + c.next_timeout(1000).await.ok(); + } + Ok(()) +} + #[cfg(test)] mod test { use super::*; diff --git a/src/platform/windows.rs b/src/platform/windows.rs index 2c89b49fb..015b6a332 100644 --- a/src/platform/windows.rs +++ b/src/platform/windows.rs @@ -76,7 +76,7 @@ pub const SET_FOREGROUND_WINDOW: &'static str = "SET_FOREGROUND_WINDOW"; const REG_NAME_INSTALL_DESKTOPSHORTCUTS: &str = "DESKTOPSHORTCUTS"; const REG_NAME_INSTALL_STARTMENUSHORTCUTS: &str = "STARTMENUSHORTCUTS"; -const REG_NAME_INSTALL_PRINTER: &str = "PRINTER"; +pub const REG_NAME_INSTALL_PRINTER: &str = "PRINTER"; pub fn get_focused_display(displays: Vec) -> Option { unsafe { @@ -1590,6 +1590,35 @@ pub fn get_license_from_exe_name() -> ResultType { get_custom_server_from_string(&exe) } +pub fn check_update_printer_option() { + if !is_installed() { + return; + } + let app_name = crate::get_app_name(); + if let Ok(b) = remote_printer::is_rd_printer_installed(&app_name) { + let v = if b { "1" } else { "0" }; + if let Err(e) = update_install_option(REG_NAME_INSTALL_PRINTER, v) { + log::error!( + "Failed to update printer option \"{}\" to \"{}\", error: {}", + REG_NAME_INSTALL_PRINTER, + v, + e + ); + } + } +} + +// We can't directly use `RegKey::set_value` to update the registry value, because it will fail with `ERROR_ACCESS_DENIED` +// So we have to use `run_cmds` to update the registry value. +pub fn update_install_option(k: &str, v: &str) -> ResultType<()> { + let app_name = crate::get_app_name(); + let ext = app_name.to_lowercase(); + let cmds = + format!("chcp 65001 && reg add HKEY_CLASSES_ROOT\\.{ext} /f /v {k} /t REG_SZ /d \"{v}\""); + run_cmds(cmds, false, "update_install_option")?; + Ok(()) +} + #[inline] pub fn is_win_server() -> bool { unsafe { is_windows_server() > 0 } diff --git a/src/server.rs b/src/server.rs index 87e6f390f..7f51e5a99 100644 --- a/src/server.rs +++ b/src/server.rs @@ -567,6 +567,8 @@ pub async fn start_server(is_server: bool, no_server: bool) { crate::platform::try_kill_broker(); #[cfg(feature = "hwcodec")] scrap::hwcodec::start_check_process(); + #[cfg(target_os = "windows")] + crate::platform::check_update_printer_option(); crate::RendezvousMediator::start_all().await; } else { match crate::ipc::connect(1000, "").await {