From 06a52e1b540e1502ae088803244f270e6b73400b Mon Sep 17 00:00:00 2001 From: fufesou Date: Thu, 13 Apr 2023 23:00:24 +0800 Subject: [PATCH 1/9] tmp commit Signed-off-by: fufesou --- Cargo.toml | 3 +- src/lib.rs | 5 +- src/platform/windows.rs | 62 ++++-- src/privacy_mode/mod.rs | 43 ++++ src/privacy_mode/privacy_win_idd.rs | 188 ++++++++++++++++++ .../privacy_win_mag.rs} | 15 +- src/server/connection.rs | 16 +- src/server/video_service.rs | 47 +++-- src/ui_cm_interface.rs | 4 +- 9 files changed, 318 insertions(+), 65 deletions(-) create mode 100644 src/privacy_mode/mod.rs create mode 100644 src/privacy_mode/privacy_win_idd.rs rename src/{win_privacy.rs => privacy_mode/privacy_win_mag.rs} (96%) diff --git a/Cargo.toml b/Cargo.toml index 3579501c7..f1c39a64d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,6 +31,7 @@ default = ["use_dasp"] hwcodec = ["scrap/hwcodec"] mediacodec = ["scrap/mediacodec"] linux_headless = ["pam", "users"] +virtual_display_driver = ["virtual_display"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -94,7 +95,7 @@ winit = "0.26" winapi = { version = "0.3", features = ["winuser", "wincrypt"] } winreg = "0.10" windows-service = "0.4" -virtual_display = { path = "libs/virtual_display" } +virtual_display = { path = "libs/virtual_display", optional = true } impersonate_system = { git = "https://github.com/21pages/impersonate-system" } shared_memory = "0.12" shutdown_hooks = "0.1" diff --git a/src/lib.rs b/src/lib.rs index 15c0ca037..7a7062b27 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -66,5 +66,6 @@ pub mod clipboard_file; #[cfg(all(windows, feature = "with_rc"))] pub mod rc; -#[cfg(target_os = "windows")] -pub mod win_privacy; + +#[cfg(not(any(target_os = "android", target_os = "ios")))] +pub mod privacy_mode; diff --git a/src/platform/windows.rs b/src/platform/windows.rs index 383259a32..ab76c8559 100644 --- a/src/platform/windows.rs +++ b/src/platform/windows.rs @@ -1,7 +1,8 @@ use super::{CursorData, ResultType}; use crate::common::PORTABLE_APPNAME_RUNTIME_ENV_KEY; -use crate::ipc; -use crate::license::*; +#[cfg(feature = "privacy_win_mag")] +use crate::privacy_mode::privacy_win_mag; +use crate::{ipc, license::*, privacy_mode::WIN_MAG_INJECTED_PROCESS_EXE}; use hbb_common::{ allow_err, bail, config::{self, Config}, @@ -9,10 +10,12 @@ use hbb_common::{ message_proto::Resolution, sleep, timeout, tokio, }; +#[cfg(feature = "privacy_win_mag")] +use std::fs; use std::{ collections::HashMap, ffi::OsString, - fs, io, + io, io::prelude::*, mem, os::windows::process::CommandExt, @@ -836,10 +839,11 @@ fn get_default_install_path() -> String { format!("{}\\{}", pf, crate::get_app_name()) } +#[cfg(feature = "privacy_win_mag")] pub fn check_update_broker_process() -> ResultType<()> { // let (_, path, _, _) = get_install_info(); - let process_exe = crate::win_privacy::INJECTED_PROCESS_EXE; - let origin_process_exe = crate::win_privacy::ORIGIN_PROCESS_EXE; + let process_exe = privacy_win_mag::INJECTED_PROCESS_EXE; + let origin_process_exe = privacy_win_mag::ORIGIN_PROCESS_EXE; let exe_file = std::env::current_exe()?; if exe_file.parent().is_none() { @@ -922,17 +926,31 @@ pub fn copy_raw_cmd(src_raw: &str, _raw: &str, _path: &str) -> String { pub fn copy_exe_cmd(src_exe: &str, exe: &str, path: &str) -> String { let main_exe = copy_raw_cmd(src_exe, exe, path); - return format!( - " - {main_exe} - copy /Y \"{ORIGIN_PROCESS_EXE}\" \"{path}\\{broker_exe}\" - \"{src_exe}\" --extract \"{path}\" - ", - main_exe = main_exe, - path = path, - ORIGIN_PROCESS_EXE = crate::win_privacy::ORIGIN_PROCESS_EXE, - broker_exe = crate::win_privacy::INJECTED_PROCESS_EXE, - ); + #[cfg(feature = "privacy_win_mag")] + { + format!( + " + {main_exe} + copy /Y \"{ORIGIN_PROCESS_EXE}\" \"{path}\\{broker_exe}\" + \"{src_exe}\" --extract \"{path}\" + ", + main_exe = main_exe, + path = path, + ORIGIN_PROCESS_EXE = privacy_win_mag::ORIGIN_PROCESS_EXE, + broker_exe = privacy_win_mag::INJECTED_PROCESS_EXE, + ) + } + #[cfg(not(feature = "privacy_win_mag"))] + { + format!( + " + {main_exe} + \"{src_exe}\" --extract \"{path}\" + ", + main_exe = main_exe, + path = path, + ) + } } pub fn update_me() -> ResultType<()> { @@ -963,7 +981,7 @@ pub fn update_me() -> ResultType<()> { ", copy_exe = copy_exe_cmd(&src_exe, &exe, &path), copy_dll = copy_dll, - broker_exe = crate::win_privacy::INJECTED_PROCESS_EXE, + broker_exe = WIN_MAG_INJECTED_PROCESS_EXE, app_name = crate::get_app_name(), lic = register_licence(), cur_pid = get_current_pid(), @@ -1257,7 +1275,7 @@ fn get_before_uninstall(kill_self: bool) -> String { netsh advfirewall firewall delete rule name=\"{app_name} Service\" ", app_name = app_name, - broker_exe = crate::win_privacy::INJECTED_PROCESS_EXE, + broker_exe = WIN_MAG_INJECTED_PROCESS_EXE, ext = ext, filter = filter, ) @@ -2180,6 +2198,14 @@ pub fn get_unicode_from_vk(vk: u32) -> Option { } } +pub fn is_process_consent_running() -> ResultType { + let output = std::process::Command::new("cmd") + .args(&["/C", "tasklist | findstr consent.exe"]) + .creation_flags(CREATE_NO_WINDOW) + .output()?; + Ok(output.status.success() && !output.stdout.is_empty()) +} + #[cfg(test)] mod tests { use super::*; diff --git a/src/privacy_mode/mod.rs b/src/privacy_mode/mod.rs new file mode 100644 index 000000000..9b21177f8 --- /dev/null +++ b/src/privacy_mode/mod.rs @@ -0,0 +1,43 @@ +use crate::ipc::PrivacyModeState; +use hbb_common::{bail, ResultType}; + +#[cfg(all(windows, feature = "privacy_win_mag"))] +pub mod privacy_win_mag; +pub const WIN_MAG_INJECTED_PROCESS_EXE: &'static str = "RuntimeBroker_rustdesk.exe"; + +pub const OCCUPIED: &'static str = "Privacy occupied by another one"; +pub const TURN_OFF_OTHER_ID: &'static str = + "Failed to turn off privacy mode that belongs to someone else"; +pub const NO_DISPLAYS: &'static str = "No displays"; + +#[cfg(all(windows, feature = "virtual_display_driver"))] +pub mod privacy_win_idd; + +pub trait PrivacyMode { + fn turn_on_privacy(&mut self, conn_id: i32) -> ResultType; + fn turn_off_privacy(&mut self, conn_id: i32, state: Option) + -> ResultType<()>; + + fn cur_conn_id(&self) -> i32; + + #[inline] + fn check_on_conn_id(&self, conn_id: i32) -> ResultType { + let pre_conn_id = self.cur_conn_id(); + if pre_conn_id == conn_id { + return Ok(true); + } + if pre_conn_id != 0 { + bail!(OCCUPIED); + } + Ok(false) + } + + #[inline] + fn check_off_conn_id(&self, conn_id: i32) -> ResultType<()> { + let pre_conn_id = self.cur_conn_id(); + if pre_conn_id != 0 && conn_id != 0 && pre_conn_id != conn_id { + bail!(TURN_OFF_OTHER_ID) + } + Ok(()) + } +} diff --git a/src/privacy_mode/privacy_win_idd.rs b/src/privacy_mode/privacy_win_idd.rs new file mode 100644 index 000000000..13798bf16 --- /dev/null +++ b/src/privacy_mode/privacy_win_idd.rs @@ -0,0 +1,188 @@ +use super::{PrivacyModeState, NO_DISPLAYS}; +use hbb_common::{allow_err, bail, lazy_static, log, ResultType}; +use scrap::dxgi; +use winapi::{ + shared::{ + minwindef::{DWORD, FALSE}, + ntdef::{NULL, WCHAR}, + }, + um::{ + errhandlingapi::GetLastError, + wingdi::{DEVMODEW, DISPLAY_DEVICEW, DISPLAY_DEVICE_ATTACHED_TO_DESKTOP, DM_POSITION}, + winuser::{ + ChangeDisplaySettingsExW, EnumDisplayDevicesW, EnumDisplaySettingsW, CDS_NORESET, + CDS_SET_PRIMARY, CDS_UPDATEREGISTRY, DISP_CHANGE_SUCCESSFUL, + EDD_GET_DEVICE_INTERFACE_NAME, ENUM_CURRENT_SETTINGS, + }, + }, +}; + +const IDD_DEVICE_STRING: &'static str = "RustDeskIddDriver Device"; + +struct Display { + dm: DEVMODEW, + name: [WCHAR; 32], + primary: bool, +} + +pub struct PrivacyModeImpl { + conn_id: i32, + displays: Vec, + virtual_displays: Vec, + virtual_displays_added: Option, +} + +impl PrivacyModeImpl { + fn set_displays(&mut self) { + self.displays.clear(); + self.virtual_displays.clear(); + for display in dxgi::Displays::get_from_gdi().into_iter() { + if let Some(gdi_info) = display.gdi() { + if let Ok(s) = std::string::String::from_utf16(&gdi_info.dd.DeviceString) { + if s == IDD_DEVICE_STRING { + self.virtual_displays.push(Display { + dm: gdi_info.dm, + name: gdi_info.dd.DeviceName, + primary: gdi_info.is_primary, + }); + continue; + } + } + self.displays.push(Display { + dm: gdi_info.dm, + name: gdi_info.dd.DeviceName, + primary: gdi_info.is_primary, + }); + } + } + } + + fn restore(&self) {} + + fn set_primary_display(&mut self) -> ResultType<()> { + self.ensure_virtual_display()?; + if self.virtual_displays.is_empty() { + bail!("No virtual displays"); + } + let display = &self.virtual_displays[0]; + + let mut new_primary_dm: DEVMODEW = unsafe { std::mem::MaybeUninit::uninit().assume_init() }; + new_primary_dm.dmSize = std::mem::size_of::() as _; + new_primary_dm.dmDriverExtra = 0; + unsafe { + if FALSE + == EnumDisplaySettingsW( + display.name.as_ptr(), + ENUM_CURRENT_SETTINGS, + &mut new_primary_dm, + ) + { + bail!( + "Failed EnumDisplaySettingsW, device name: {:?}, error code: {}", + std::string::String::from_utf16(&display.name), + GetLastError() + ); + } + + let mut i: DWORD = 0; + loop { + let mut flags = CDS_UPDATEREGISTRY | CDS_NORESET; + let mut dd: DISPLAY_DEVICEW = std::mem::MaybeUninit::uninit().assume_init(); + dd.cb = std::mem::size_of::() as _; + if FALSE + == EnumDisplayDevicesW(NULL as _, i, &mut dd, EDD_GET_DEVICE_INTERFACE_NAME) + { + break; + } + i += 1; + if (dd.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP) == 0 { + continue; + } + + if dd.DeviceName == display.name { + flags |= CDS_SET_PRIMARY; + } + + let mut dm: DEVMODEW = std::mem::MaybeUninit::uninit().assume_init(); + dm.dmSize = std::mem::size_of::() as _; + dm.dmDriverExtra = 0; + if FALSE + == EnumDisplaySettingsW(dd.DeviceName.as_ptr(), ENUM_CURRENT_SETTINGS, &mut dm) + { + bail!( + "Failed EnumDisplaySettingsW, device name: {:?}, error code: {}", + std::string::String::from_utf16(&dd.DeviceName), + GetLastError() + ); + } + + dm.u1.s2_mut().dmPosition.x -= new_primary_dm.u1.s2().dmPosition.x; + dm.u1.s2_mut().dmPosition.y -= new_primary_dm.u1.s2().dmPosition.y; + dm.dmFields |= DM_POSITION; + let rc = ChangeDisplaySettingsExW( + dd.DeviceName.as_ptr(), + &mut dm, + NULL as _, + flags, + NULL, + ); + + if rc != DISP_CHANGE_SUCCESSFUL { + log::error!( + "Failed ChangeDisplaySettingsEx, device name: {:?}, flags: {}, ret: {}", + std::string::String::from_utf16(&dd.DeviceName), + flags, + rc + ); + bail!("Failed ChangeDisplaySettingsEx, ret: {}", rc); + } + } + } + + Ok(()) + } + + fn ensure_virtual_display(&mut self) -> ResultType<()> { + if self.virtual_displays.is_empty() { + virtual_display::create_device()?; + } + if virtual_display::is_device_created() { + // to-do: add monitor index here + virtual_display::plug_in_monitor()?; + self.virtual_displays_added = Some(0); + } + + self.set_displays(); + Ok(()) + } +} + +impl super::PrivacyMode for PrivacyModeImpl { + fn turn_on_privacy(&mut self, conn_id: i32) -> ResultType { + if self.check_on_conn_id(conn_id)? { + return Ok(true); + } + self.set_displays(); + if self.displays.is_empty() { + bail!(NO_DISPLAYS); + } + self.set_primary_display()?; + + bail!("unimplemented") + } + + fn turn_off_privacy( + &mut self, + conn_id: i32, + state: Option, + ) -> ResultType<()> { + self.check_off_conn_id(conn_id)?; + self.restore(); + bail!("unimplemented") + } + + #[inline] + fn cur_conn_id(&self) -> i32 { + self.conn_id + } +} diff --git a/src/win_privacy.rs b/src/privacy_mode/privacy_win_mag.rs similarity index 96% rename from src/win_privacy.rs rename to src/privacy_mode/privacy_win_mag.rs index 9944bf262..923c42859 100644 --- a/src/win_privacy.rs +++ b/src/privacy_mode/privacy_win_mag.rs @@ -5,7 +5,6 @@ use crate::{ use hbb_common::{allow_err, bail, lazy_static, log, tokio, ResultType}; use std::{ ffi::CString, - os::windows::process::CommandExt, sync::Mutex, time::{Duration, Instant}, }; @@ -25,16 +24,14 @@ use winapi::{ CreateProcessAsUserW, GetCurrentThreadId, QueueUserAPC, ResumeThread, PROCESS_INFORMATION, STARTUPINFOW, }, - winbase::{ - WTSGetActiveConsoleSessionId, CREATE_NO_WINDOW, CREATE_SUSPENDED, DETACHED_PROCESS, - }, + winbase::{WTSGetActiveConsoleSessionId, CREATE_SUSPENDED, DETACHED_PROCESS}, winnt::{MEM_COMMIT, PAGE_READWRITE}, winuser::*, }, }; pub const ORIGIN_PROCESS_EXE: &'static str = "C:\\Windows\\System32\\RuntimeBroker.exe"; -pub const INJECTED_PROCESS_EXE: &'static str = "RuntimeBroker_rustdesk.exe"; +pub const INJECTED_PROCESS_EXE: &'static str = super::WIN_MAG_INJECTED_PROCESS_EXE; pub const PRIVACY_WINDOW_NAME: &'static str = "RustDeskPrivacyWindow"; pub const GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT: u32 = 2; @@ -317,14 +314,6 @@ fn wait_find_privacy_hwnd(msecs: u128) -> ResultType { } } -pub fn is_process_consent_running() -> ResultType { - let output = std::process::Command::new("cmd") - .args(&["/C", "tasklist | findstr consent.exe"]) - .creation_flags(CREATE_NO_WINDOW) - .output()?; - Ok(output.status.success() && !output.stdout.is_empty()) -} - #[tokio::main(flavor = "current_thread")] async fn set_privacy_mode_state( conn_id: i32, diff --git a/src/server/connection.rs b/src/server/connection.rs index 8a6ba99b9..25dea58ad 100644 --- a/src/server/connection.rs +++ b/src/server/connection.rs @@ -2346,13 +2346,13 @@ fn try_activate_screen() { mod privacy_mode { use super::*; + #[cfg(all(windows, feature = "privacy_win_mag"))] + use crate::privacy_mode::privacy_win_mag; pub(super) fn turn_off_privacy(_conn_id: i32) -> Message { - #[cfg(windows)] + #[cfg(all(windows, feature = "privacy_win_mag"))] { - use crate::win_privacy::*; - - let res = turn_off_privacy(_conn_id, None); + let res = privacy_win_mag::turn_off_privacy(_conn_id, None); match res { Ok(_) => crate::common::make_privacy_mode_msg( back_notification::PrivacyModeState::PrvOffSucceeded, @@ -2365,19 +2365,19 @@ mod privacy_mode { } } } - #[cfg(not(windows))] + #[cfg(not(all(windows, feature = "privacy_win_mag")))] { crate::common::make_privacy_mode_msg(back_notification::PrivacyModeState::PrvOffFailed) } } pub(super) fn turn_on_privacy(_conn_id: i32) -> ResultType { - #[cfg(windows)] + #[cfg(all(windows, feature = "privacy_win_mag"))] { - let plugin_exist = crate::win_privacy::turn_on_privacy(_conn_id)?; + let plugin_exist = privacy_win_mag::turn_on_privacy(_conn_id)?; Ok(plugin_exist) } - #[cfg(not(windows))] + #[cfg(not(all(windows, feature = "privacy_win_mag")))] { Ok(true) } diff --git a/src/server/video_service.rs b/src/server/video_service.rs index 4abeafff5..e6a4e3806 100644 --- a/src/server/video_service.rs +++ b/src/server/video_service.rs @@ -20,6 +20,10 @@ use super::{video_qos::VideoQoS, *}; #[cfg(windows)] +use crate::platform::windows::is_process_consent_running; +#[cfg(all(windows, feature = "privacy_win_mag"))] +use crate::privacy_mode::privacy_win_mag; +#[cfg(all(windows, feature = "privacy_win_mag"))] use hbb_common::get_version_number; use hbb_common::tokio::sync::{ mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender}, @@ -41,7 +45,7 @@ use std::{ ops::{Deref, DerefMut}, time::{self, Duration, Instant}, }; -#[cfg(windows)] +#[cfg(all(windows, feature = "virtual_display_driver"))] use virtual_display; pub const SCRAP_UBUNTU_HIGHER_REQUIRED: &str = "Wayland requires Ubuntu 21.04 or higher version."; @@ -69,9 +73,9 @@ lazy_static::lazy_static! { } fn is_capturer_mag_supported() -> bool { - #[cfg(windows)] + #[cfg(all(windows, feature = "privacy_win_mag"))] return scrap::CapturerMag::is_supported(); - #[cfg(not(windows))] + #[cfg(not(all(windows, feature = "privacy_win_mag")))] false } @@ -92,10 +96,10 @@ pub fn get_privacy_mode_conn_id() -> i32 { } pub fn is_privacy_mode_supported() -> bool { - #[cfg(windows)] + #[cfg(all(windows, feature = "privacy_win_mag"))] return *IS_CAPTURER_MAGNIFIER_SUPPORTED && get_version_number(&crate::VERSION) > get_version_number("1.1.9"); - #[cfg(not(windows))] + #[cfg(not(all(windows, feature = "privacy_win_mag")))] return false; } @@ -201,15 +205,13 @@ fn create_capturer( _current: usize, _portable_service_running: bool, ) -> ResultType> { - #[cfg(not(windows))] + #[cfg(not(all(windows, feature = "privacy_win_mag")))] let c: Option> = None; - #[cfg(windows)] + #[cfg(all(windows, feature = "privacy_win_mag"))] let mut c: Option> = None; if privacy_mode_id > 0 { - #[cfg(windows)] + #[cfg(all(windows, feature = "privacy_win_mag"))] { - use crate::win_privacy::*; - match scrap::CapturerMag::new( display.origin(), display.width(), @@ -220,7 +222,7 @@ fn create_capturer( let mut ok = false; let check_begin = Instant::now(); while check_begin.elapsed().as_secs() < 5 { - match c1.exclude("", PRIVACY_WINDOW_NAME) { + match c1.exclude("", privacy_win_mag::PRIVACY_WINDOW_NAME) { Ok(false) => { ok = false; std::thread::sleep(std::time::Duration::from_millis(500)); @@ -229,7 +231,7 @@ fn create_capturer( bail!( "Failed to exclude privacy window {} - {}, err: {}", "", - PRIVACY_WINDOW_NAME, + privacy_win_mag::PRIVACY_WINDOW_NAME, e ); } @@ -243,7 +245,7 @@ fn create_capturer( bail!( "Failed to exclude privacy window {} - {} ", "", - PRIVACY_WINDOW_NAME + privacy_win_mag::PRIVACY_WINDOW_NAME ); } log::debug!("Create magnifier capture for {}", privacy_mode_id); @@ -275,7 +277,8 @@ fn create_capturer( }; } -#[cfg(windows)] +// to-do: do not close if in privacy mode. +#[cfg(all(windows, feature = "virtual_display_driver"))] fn ensure_close_virtual_device() -> ResultType<()> { let num_displays = Display::all()?.len(); if num_displays == 0 { @@ -309,11 +312,11 @@ pub fn test_create_capturer(privacy_mode_id: i32, timeout_millis: u64) -> bool { fn check_uac_switch(privacy_mode_id: i32, capturer_privacy_mode_id: i32) -> ResultType<()> { if capturer_privacy_mode_id != 0 { if privacy_mode_id != capturer_privacy_mode_id { - if !crate::win_privacy::is_process_consent_running()? { + if !is_process_consent_running()? { bail!("consent.exe is running"); } } - if crate::win_privacy::is_process_consent_running()? { + if is_process_consent_running()? { bail!("consent.exe is running"); } } @@ -374,7 +377,7 @@ fn get_capturer(use_yuv: bool, portable_service_running: bool) -> ResultType Option { } fn run(sp: GenericService) -> ResultType<()> { - #[cfg(windows)] + #[cfg(all(windows, feature = "virtual_display_driver"))] ensure_close_virtual_device()?; // ensure_inited() is needed because release_resource() may be called. @@ -922,12 +925,12 @@ pub async fn switch_to_primary() { } #[inline] -#[cfg(not(windows))] +#[cfg(not(all(windows, feature = "virtual_display_driver")))] fn try_get_displays() -> ResultType> { Ok(Display::all()?) } -#[cfg(windows)] +#[cfg(all(windows, feature = "virtual_display_driver"))] fn try_get_displays() -> ResultType> { let mut displays = Display::all()?; if displays.len() == 0 { @@ -949,6 +952,8 @@ fn try_get_displays() -> ResultType> { } displays = Display::all()?; } else if displays.len() > 1 { + // to-do: do not close if in privacy mode. + // If more than one displays exists, close RustDeskVirtualDisplay if virtual_display::is_device_created() { virtual_display::close_device() @@ -991,7 +996,7 @@ fn start_uac_elevation_check() { if !crate::platform::is_installed() && !crate::platform::is_root() { std::thread::spawn(|| loop { std::thread::sleep(std::time::Duration::from_secs(1)); - if let Ok(uac) = crate::win_privacy::is_process_consent_running() { + if let Ok(uac) = is_process_consent_running() { *IS_UAC_RUNNING.lock().unwrap() = uac; } if !crate::platform::is_elevated(None).unwrap_or(false) { diff --git a/src/ui_cm_interface.rs b/src/ui_cm_interface.rs index 8612b5751..b738bd4ac 100644 --- a/src/ui_cm_interface.rs +++ b/src/ui_cm_interface.rs @@ -495,7 +495,7 @@ impl IpcTaskRunner { #[cfg(not(any(target_os = "android", target_os = "ios")))] #[tokio::main(flavor = "current_thread")] pub async fn start_ipc(cm: ConnectionManager) { - #[cfg(windows)] + #[cfg(all(windows, feature = "privacy_win_mag"))] std::thread::spawn(move || { log::info!("try create privacy mode window"); if let Err(e) = crate::platform::windows::check_update_broker_process() { @@ -504,7 +504,7 @@ pub async fn start_ipc(cm: ConnectionManager) { e ); } - allow_err!(crate::win_privacy::start()); + allow_err!(crate::privacy_mode::privacy_win_mag::start()); }); match ipc::new_listener("_cm").await { From 29887440346fdf8b61c792795625e2abbe41198a Mon Sep 17 00:00:00 2001 From: fufesou Date: Fri, 14 Apr 2023 09:42:46 +0800 Subject: [PATCH 2/9] mid commit Signed-off-by: fufesou --- libs/scrap/src/dxgi/mod.rs | 78 ++++++++++++++++++++++++-------------- 1 file changed, 50 insertions(+), 28 deletions(-) diff --git a/libs/scrap/src/dxgi/mod.rs b/libs/scrap/src/dxgi/mod.rs index 4a0a53402..2d9bd636f 100644 --- a/libs/scrap/src/dxgi/mod.rs +++ b/libs/scrap/src/dxgi/mod.rs @@ -62,7 +62,7 @@ impl Capturer { let mut desc = unsafe { mem::MaybeUninit::uninit().assume_init() }; let mut gdi_capturer = None; - let mut res = if display.gdi { + let mut res = if display.gdi.is_some() { wrap_hresult(1) } else { wrap_hresult(unsafe { @@ -367,48 +367,60 @@ impl Displays { let mut i: DWORD = 0; loop { #[allow(invalid_value)] - let mut d: DISPLAY_DEVICEW = unsafe { std::mem::MaybeUninit::uninit().assume_init() }; - d.cb = std::mem::size_of::() as _; - let ok = unsafe { EnumDisplayDevicesW(std::ptr::null(), i, &mut d as _, 0) }; + let mut dd: DISPLAY_DEVICEW = unsafe { std::mem::MaybeUninit::uninit().assume_init() }; + dd.cb = std::mem::size_of::() as _; + let ok = unsafe { EnumDisplayDevicesW(std::ptr::null(), i, &mut dd as _, 0) }; if ok == FALSE { break; } i += 1; - if 0 == (d.StateFlags & DISPLAY_DEVICE_ACTIVE) - || (d.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) > 0 + if 0 == (dd.StateFlags & DISPLAY_DEVICE_ACTIVE) + || (dd.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) > 0 { continue; } - // let is_primary = (d.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) > 0; let mut disp = Display { inner: ComPtr(std::ptr::null_mut()), adapter: ComPtr(std::ptr::null_mut()), desc: unsafe { std::mem::zeroed() }, - gdi: true, + gdi: None, }; - disp.desc.DeviceName = d.DeviceName; + disp.desc.DeviceName = dd.DeviceName.clone(); #[allow(invalid_value)] - let mut m: DEVMODEW = unsafe { std::mem::MaybeUninit::uninit().assume_init() }; - m.dmSize = std::mem::size_of::() as _; - m.dmDriverExtra = 0; - let ok = unsafe { - EnumDisplaySettingsExW( - disp.desc.DeviceName.as_ptr(), - ENUM_CURRENT_SETTINGS, - &mut m as _, - 0, - ) - }; - if ok == FALSE { - continue; + let mut dm: DEVMODEW = unsafe { std::mem::MaybeUninit::uninit().assume_init() }; + dm.dmSize = std::mem::size_of::() as _; + dm.dmDriverExtra = 0; + unsafe { + if FALSE + == EnumDisplaySettingsExW( + disp.desc.DeviceName.as_ptr(), + ENUM_CURRENT_SETTINGS, + &mut dm as _, + 0, + ) + { + if FALSE + == EnumDisplaySettingsExW( + disp.desc.DeviceName.as_ptr(), + ENUM_REGISTRY_SETTINGS, + &mut dm as _, + 0, + ) + { + continue; + } + } } - disp.desc.DesktopCoordinates.left = unsafe { m.u1.s2().dmPosition.x }; - disp.desc.DesktopCoordinates.top = unsafe { m.u1.s2().dmPosition.y }; + disp.desc.DesktopCoordinates.left = unsafe { dm.u1.s2().dmPosition.x }; + disp.desc.DesktopCoordinates.top = unsafe { dm.u1.s2().dmPosition.y }; disp.desc.DesktopCoordinates.right = - disp.desc.DesktopCoordinates.left + m.dmPelsWidth as i32; + disp.desc.DesktopCoordinates.left + dm.dmPelsWidth as i32; disp.desc.DesktopCoordinates.bottom = - disp.desc.DesktopCoordinates.top + m.dmPelsHeight as i32; + disp.desc.DesktopCoordinates.top + dm.dmPelsHeight as i32; disp.desc.AttachedToDesktop = 1; + + let is_primary = (dd.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) > 0; + disp.gdi = Some(GdiDisplayInfo { dd, dm, is_primary }); all.push(disp); } all @@ -476,7 +488,7 @@ impl Displays { inner: ComPtr(inner), adapter: ComPtr(self.adapter.0), desc, - gdi: false, + gdi: None, })) } } @@ -512,7 +524,13 @@ pub struct Display { inner: ComPtr, adapter: ComPtr, desc: DXGI_OUTPUT_DESC, - gdi: bool, + gdi: Option, +} + +pub struct GdiDisplayInfo { + pub dd: DISPLAY_DEVICEW, + pub dm: DEVMODEW, + pub is_primary: bool, } // optimized for updated region @@ -537,6 +555,10 @@ impl Display { self.desc.Rotation } + pub fn gdi(&self) -> &Option { + &self.gdi + } + fn create_gdi(&self) -> Option { if let Ok(res) = CapturerGDI::new(self.name(), self.width(), self.height()) { Some(res) From 35ec3ffef6d404b5744be7e849886a06e42451b4 Mon Sep 17 00:00:00 2001 From: fufesou Date: Fri, 14 Apr 2023 21:31:12 +0800 Subject: [PATCH 3/9] tmp commit Signed-off-by: fufesou --- Cargo.lock | 3 +- Cargo.toml | 1 - libs/hbb_common/Cargo.toml | 1 + libs/hbb_common/src/config.rs | 15 ++ libs/hbb_common/src/lib.rs | 2 + libs/virtual_display/Cargo.toml | 1 - libs/virtual_display/dylib/src/lib.rs | 101 +++----- .../examples/virtual_display_1.rs | 19 +- libs/virtual_display/src/lib.rs | 243 +++++++++++------- src/flutter.rs | 15 +- src/server/video_service.rs | 28 +- 11 files changed, 253 insertions(+), 176 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 505a6f2d6..098189693 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2776,6 +2776,7 @@ dependencies = [ "confy", "directories-next", "dirs-next", + "dlopen", "env_logger 0.10.0", "filetime", "flexi_logger", @@ -5118,7 +5119,6 @@ dependencies = [ "dbus-crossroads", "default-net", "dispatch", - "dlopen", "enigo", "errno", "evdev", @@ -6451,7 +6451,6 @@ version = "0.1.0" dependencies = [ "hbb_common", "lazy_static", - "libloading", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index f1c39a64d..94ef44e0f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -65,7 +65,6 @@ flutter_rust_bridge = { version = "1.61.1", optional = true } errno = "0.3" rdev = { git = "https://github.com/fufesou/rdev" } url = { version = "2.1", features = ["serde"] } -dlopen = "0.1" crossbeam-queue = "0.3" hex = "0.4" reqwest = { version = "0.11", features = ["blocking", "json", "rustls-tls"], default-features=false } diff --git a/libs/hbb_common/Cargo.toml b/libs/hbb_common/Cargo.toml index ed9ec73be..4ce9ef37e 100644 --- a/libs/hbb_common/Cargo.toml +++ b/libs/hbb_common/Cargo.toml @@ -34,6 +34,7 @@ tokio-socks = { git = "https://github.com/open-trade/tokio-socks" } chrono = "0.4" backtrace = "0.3" libc = "0.2" +dlopen = "0.1" [target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies] mac_address = "1.1" diff --git a/libs/hbb_common/src/config.rs b/libs/hbb_common/src/config.rs index 369920982..8786858e2 100644 --- a/libs/hbb_common/src/config.rs +++ b/libs/hbb_common/src/config.rs @@ -1141,6 +1141,8 @@ pub struct LocalConfig { // Various data for flutter ui #[serde(default)] ui_flutter: HashMap, + #[serde(default)] + virtual_display_num: usize, } impl LocalConfig { @@ -1243,6 +1245,19 @@ impl LocalConfig { config.store(); } } + + pub fn get_virtual_display_num() -> usize { + LOCAL_CONFIG.read().unwrap().virtual_display_num + } + + pub fn set_virtual_display_num(virtual_display_num: usize) { + let mut lock = LOCAL_CONFIG.write().unwrap(); + if lock.virtual_display_num == virtual_display_num { + return; + } + lock.virtual_display_num = virtual_display_num; + lock.store(); + } } #[derive(Debug, Default, Serialize, Deserialize, Clone)] diff --git a/libs/hbb_common/src/lib.rs b/libs/hbb_common/src/lib.rs index 799093d24..7d841613d 100644 --- a/libs/hbb_common/src/lib.rs +++ b/libs/hbb_common/src/lib.rs @@ -44,6 +44,8 @@ pub use libc; pub mod keyboard; #[cfg(not(any(target_os = "android", target_os = "ios")))] pub use sysinfo; +#[cfg(not(any(target_os = "android", target_os = "ios")))] +pub use dlopen; #[cfg(feature = "quic")] pub type Stream = quic::Connection; diff --git a/libs/virtual_display/Cargo.toml b/libs/virtual_display/Cargo.toml index c700bd12a..2c2372212 100644 --- a/libs/virtual_display/Cargo.toml +++ b/libs/virtual_display/Cargo.toml @@ -7,5 +7,4 @@ edition = "2021" [dependencies] lazy_static = "1.4" -libloading = "0.7" hbb_common = { path = "../hbb_common" } diff --git a/libs/virtual_display/dylib/src/lib.rs b/libs/virtual_display/dylib/src/lib.rs index 4a95e3461..3b83d297c 100644 --- a/libs/virtual_display/dylib/src/lib.rs +++ b/libs/virtual_display/dylib/src/lib.rs @@ -2,18 +2,21 @@ pub mod win10; use hbb_common::{bail, lazy_static, ResultType}; -use std::{path::Path, sync::Mutex}; +use std::path::Path; +#[cfg(windows)] +use std::sync::Mutex; + +#[cfg(windows)] lazy_static::lazy_static! { // If device is uninstalled though "Device Manager" Window. // Rustdesk is unable to handle device any more... static ref H_SW_DEVICE: Mutex = Mutex::new(0); - static ref MONITOR_PLUGIN: Mutex> = Mutex::new(Vec::new()); } #[no_mangle] #[cfg(windows)] -pub fn get_dirver_install_path() -> &'static str { +pub fn get_driver_install_path() -> &'static str { win10::DRIVER_INSTALL_PATH } @@ -137,68 +140,48 @@ pub fn close_device() { unsafe { win10::idd::DeviceClose(*H_SW_DEVICE.lock().unwrap() as win10::idd::HSWDEVICE); *H_SW_DEVICE.lock().unwrap() = 0; - MONITOR_PLUGIN.lock().unwrap().clear(); } } #[no_mangle] -pub fn plug_in_monitor() -> ResultType<()> { +pub fn plug_in_monitor(_monitor_index: u32, _edid: u32, _retries: u32) -> ResultType<()> { #[cfg(windows)] unsafe { - let monitor_index = 0 as u32; - let mut plug_in_monitors = MONITOR_PLUGIN.lock().unwrap(); - for i in 0..plug_in_monitors.len() { - if let Some(d) = plug_in_monitors.get(i) { - if *d == monitor_index { - return Ok(()); - } - }; - } - if win10::idd::MonitorPlugIn(monitor_index, 0, 30) == win10::idd::FALSE { - bail!("{}", win10::get_last_msg()?); - } - (*plug_in_monitors).push(monitor_index); - } - Ok(()) -} - -#[no_mangle] -pub fn plug_out_monitor() -> ResultType<()> { - #[cfg(windows)] - unsafe { - let monitor_index = 0 as u32; - if win10::idd::MonitorPlugOut(monitor_index) == win10::idd::FALSE { - bail!("{}", win10::get_last_msg()?); - } - let mut plug_in_monitors = MONITOR_PLUGIN.lock().unwrap(); - for i in 0..plug_in_monitors.len() { - if let Some(d) = plug_in_monitors.get(i) { - if *d == monitor_index { - plug_in_monitors.remove(i); - break; - } - }; - } - } - Ok(()) -} - -#[no_mangle] -pub fn update_monitor_modes() -> ResultType<()> { - #[cfg(windows)] - unsafe { - let monitor_index = 0 as u32; - let mut modes = vec![win10::idd::MonitorMode { - width: 1920, - height: 1080, - sync: 60, - }]; - if win10::idd::FALSE - == win10::idd::MonitorModesUpdate( - monitor_index as win10::idd::UINT, - modes.len() as win10::idd::UINT, - modes.as_mut_ptr(), - ) + if win10::idd::MonitorPlugIn(_monitor_index as _, _edid as _, _retries as _) + == win10::idd::FALSE + { + bail!("{}", win10::get_last_msg()?); + } + } + Ok(()) +} + +#[no_mangle] +pub fn plug_out_monitor(_monitor_index: u32) -> ResultType<()> { + #[cfg(windows)] + unsafe { + if win10::idd::MonitorPlugOut(_monitor_index) == win10::idd::FALSE { + bail!("{}", win10::get_last_msg()?); + } + } + Ok(()) +} + +#[cfg(windows)] +type PMonitorMode = win10::idd::PMonitorMode; +#[cfg(not(windows))] +type PMonitorMode = *mut std::ffi::c_void; + +#[no_mangle] +pub fn update_monitor_modes( + _monitor_index: u32, + _mode_count: u32, + _modes: PMonitorMode, +) -> ResultType<()> { + #[cfg(windows)] + unsafe { + if win10::idd::FALSE + == win10::idd::MonitorModesUpdate(_monitor_index as _, _mode_count as _, _modes) { bail!("{}", win10::get_last_msg()?); } diff --git a/libs/virtual_display/examples/virtual_display_1.rs b/libs/virtual_display/examples/virtual_display_1.rs index 31fdbe06e..1471e3faf 100644 --- a/libs/virtual_display/examples/virtual_display_1.rs +++ b/libs/virtual_display/examples/virtual_display_1.rs @@ -18,18 +18,18 @@ fn prompt_input() -> u8 { .unwrap_or(0) } -fn plug_in() { +fn plug_in(monitor_index: u32) { println!("Plug in monitor begin"); - if let Err(e) = virtual_display::plug_in_monitor() { + if let Err(e) = virtual_display::plug_in_monitor(monitor_index as _) { println!("{}", e); } else { println!("Plug in monitor done"); } } -fn plug_out() { +fn plug_out(monitor_index: u32) { println!("Plug out monitor begin"); - if let Err(e) = virtual_display::plug_out_monitor() { + if let Err(e) = virtual_display::plug_out_monitor(monitor_index as _) { println!("{}", e); } else { println!("Plug out monitor done"); @@ -38,7 +38,8 @@ fn plug_out() { fn main() { loop { - match prompt_input() as char { + let chr = prompt_input(); + match chr as char { 'x' => break, 'i' => { println!("Install or update driver begin"); @@ -81,8 +82,12 @@ fn main() { virtual_display::close_device(); println!("Close device done"); } - '1' => plug_in(), - '4' => plug_out(), + '1' => plug_in(0), + '2' => plug_in(1), + '3' => plug_in(2), + '4' => plug_out(0), + '5' => plug_out(1), + '6' => plug_out(2), _ => {} } } diff --git a/libs/virtual_display/src/lib.rs b/libs/virtual_display/src/lib.rs index cd9402c69..f7e904537 100644 --- a/libs/virtual_display/src/lib.rs +++ b/libs/virtual_display/src/lib.rs @@ -1,12 +1,93 @@ -use hbb_common::{bail, ResultType}; -use std::sync::{Arc, Mutex}; +use hbb_common::{anyhow, dlopen::symbor::Library, log, ResultType}; +use std::{ + collections::HashSet, + sync::{Arc, Mutex}, +}; const LIB_NAME_VIRTUAL_DISPLAY: &str = "dylib_virtual_display"; +pub type DWORD = ::std::os::raw::c_ulong; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _MonitorMode { + pub width: DWORD, + pub height: DWORD, + pub sync: DWORD, +} +pub type MonitorMode = _MonitorMode; +pub type PMonitorMode = *mut MonitorMode; + +pub type GetDriverInstallPath = fn() -> &'static str; +pub type IsDeviceCreated = fn() -> bool; +pub type CloseDevice = fn(); +pub type DownLoadDriver = fn() -> ResultType<()>; +pub type CreateDevice = fn() -> ResultType<()>; +pub type InstallUpdateDriver = fn(&mut bool) -> ResultType<()>; +pub type UninstallDriver = fn(&mut bool) -> ResultType<()>; +pub type PlugInMonitor = fn(u32) -> ResultType<()>; +pub type PlugOutMonitor = fn(u32) -> ResultType<()>; +pub type UpdateMonitorModes = fn(u32, u32, PMonitorMode) -> ResultType<()>; + +macro_rules! make_lib_wrapper { + ($($field:ident : $tp:ty),+) => { + struct LibWrapper { + _lib: Option, + $($field: Option<$tp>),+ + } + + impl LibWrapper { + fn new() -> Self { + let lib = match Library::open(get_lib_name()) { + Ok(lib) => Some(lib), + Err(e) => { + log::warn!("Failed to load library {}, {}", LIB_NAME_VIRTUAL_DISPLAY, e); + None + } + }; + + $(let $field = if let Some(lib) = &lib { + match unsafe { lib.symbol::<$tp>(stringify!($field)) } { + Ok(m) => Some(*m), + Err(e) => { + log::warn!("Failed to load func {}, {}", stringify!($field), e); + None + } + } + } else { + None + };)+ + + Self { + _lib: lib, + $( $field ),+ + } + } + } + + impl Default for LibWrapper { + fn default() -> Self { + Self::new() + } + } + } +} + +make_lib_wrapper!( + get_driver_install_path: GetDriverInstallPath, + is_device_created: IsDeviceCreated, + close_device: CloseDevice, + download_driver: DownLoadDriver, + create_device: CreateDevice, + install_update_driver: InstallUpdateDriver, + uninstall_driver: UninstallDriver, + plug_in_monitor: PlugInMonitor, + plug_out_monitor: PlugOutMonitor, + update_monitor_modes: UpdateMonitorModes +); + lazy_static::lazy_static! { - static ref LIB_VIRTUAL_DISPLAY: Arc>> = { - Arc::new(Mutex::new(unsafe { libloading::Library::new(get_lib_name()) })) - }; + static ref LIB_WRAPPER: Arc> = Default::default(); + static ref MONITOR_INDICES: Mutex> = Mutex::new(HashSet::new()); } #[cfg(target_os = "windows")] @@ -24,102 +105,90 @@ fn get_lib_name() -> String { format!("lib{}.dylib", LIB_NAME_VIRTUAL_DISPLAY) } -fn try_reload_lib() { - let mut lock = LIB_VIRTUAL_DISPLAY.lock().unwrap(); - if lock.is_err() { - *lock = unsafe { libloading::Library::new(get_lib_name()) }; - } -} - #[cfg(windows)] -pub fn get_dirver_install_path() -> ResultType<&'static str> { - try_reload_lib(); - match &*LIB_VIRTUAL_DISPLAY.lock().unwrap() { - Ok(lib) => unsafe { - match lib.get:: &'static str>>(b"get_dirver_install_path") { - Ok(func) => Ok(func()), - Err(e) => bail!("Failed to load func get_dirver_install_path, {}", e), - } - }, - Err(e) => bail!("Failed to load library {}, {}", LIB_NAME_VIRTUAL_DISPLAY, e), - } +pub fn get_driver_install_path() -> Option<&'static str> { + Some(LIB_WRAPPER.lock().unwrap().get_driver_install_path?()) } pub fn is_device_created() -> bool { - try_reload_lib(); - match &*LIB_VIRTUAL_DISPLAY.lock().unwrap() { - Ok(lib) => unsafe { - match lib.get:: bool>>(b"is_device_created") { - Ok(func) => func(), - Err(..) => false, - } - }, - Err(..) => false, - } + LIB_WRAPPER + .lock() + .unwrap() + .is_device_created + .map(|f| f()) + .unwrap_or(false) } pub fn close_device() { - try_reload_lib(); - match &*LIB_VIRTUAL_DISPLAY.lock().unwrap() { - Ok(lib) => unsafe { - match lib.get::>(b"close_device") { - Ok(func) => func(), - Err(..) => {} - } - }, - Err(..) => {} - } + let _r = LIB_WRAPPER.lock().unwrap().close_device.map(|f| f()); } -macro_rules! def_func_result { - ($func:ident, $name: tt) => { - pub fn $func() -> ResultType<()> { - try_reload_lib(); - match &*LIB_VIRTUAL_DISPLAY.lock().unwrap() { - Ok(lib) => unsafe { - match lib.get:: ResultType<()>>>($name.as_bytes()) { - Ok(func) => func(), - Err(e) => bail!("Failed to load func {}, {}", $name, e), - } - }, - Err(e) => bail!("Failed to load library {}, {}", LIB_NAME_VIRTUAL_DISPLAY, e), - } - } - }; +pub fn download_driver() -> ResultType<()> { + LIB_WRAPPER + .lock() + .unwrap() + .download_driver + .ok_or(anyhow::Error::msg("download_driver method not found"))?() +} + +pub fn create_device() -> ResultType<()> { + LIB_WRAPPER + .lock() + .unwrap() + .create_device + .ok_or(anyhow::Error::msg("create_device method not found"))?() } pub fn install_update_driver(reboot_required: &mut bool) -> ResultType<()> { - try_reload_lib(); - match &*LIB_VIRTUAL_DISPLAY.lock().unwrap() { - Ok(lib) => unsafe { - match lib.get:: ResultType<()>>>( - b"install_update_driver", - ) { - Ok(func) => func(reboot_required), - Err(e) => bail!("Failed to load func install_update_driver, {}", e), - } - }, - Err(e) => bail!("Failed to load library {}, {}", LIB_NAME_VIRTUAL_DISPLAY, e), - } + LIB_WRAPPER + .lock() + .unwrap() + .install_update_driver + .ok_or(anyhow::Error::msg("install_update_driver method not found"))?(reboot_required) } pub fn uninstall_driver(reboot_required: &mut bool) -> ResultType<()> { - try_reload_lib(); - match &*LIB_VIRTUAL_DISPLAY.lock().unwrap() { - Ok(lib) => unsafe { - match lib - .get:: ResultType<()>>>(b"uninstall_driver") - { - Ok(func) => func(reboot_required), - Err(e) => bail!("Failed to load func uninstall_driver, {}", e), - } - }, - Err(e) => bail!("Failed to load library {}, {}", LIB_NAME_VIRTUAL_DISPLAY, e), - } + LIB_WRAPPER + .lock() + .unwrap() + .uninstall_driver + .ok_or(anyhow::Error::msg("uninstall_driver method not found"))?(reboot_required) } -def_func_result!(download_driver, "download_driver"); -def_func_result!(create_device, "create_device"); -def_func_result!(plug_in_monitor, "plug_in_monitor"); -def_func_result!(plug_out_monitor, "plug_out_monitor"); -def_func_result!(update_monitor_modes, "update_monitor_modes"); +#[cfg(windows)] +pub fn plug_in_monitor(monitor_index: u32) -> ResultType<()> { + let mut lock = MONITOR_INDICES.lock().unwrap(); + if lock.contains(&monitor_index) { + return Ok(()); + } + let f = LIB_WRAPPER + .lock() + .unwrap() + .plug_in_monitor + .ok_or(anyhow::Error::msg("plug_in_monitor method not found"))?; + f(monitor_index)?; + lock.insert(monitor_index); + Ok(()) +} + +#[cfg(windows)] +pub fn plug_out_monitor(monitor_index: u32) -> ResultType<()> { + let f = LIB_WRAPPER + .lock() + .unwrap() + .plug_out_monitor + .ok_or(anyhow::Error::msg("plug_out_monitor method not found"))?; + f(monitor_index)?; + MONITOR_INDICES.lock().unwrap().remove(&monitor_index); + Ok(()) +} + +#[cfg(windows)] +pub fn update_monitor_modes(monitor_index: u32, modes: &[MonitorMode]) -> ResultType<()> { + let f = LIB_WRAPPER + .lock() + .unwrap() + .update_monitor_modes + .ok_or(anyhow::Error::msg("update_monitor_modes method not found"))?; + f(monitor_index, modes.len() as _, modes.as_ptr() as _) +} diff --git a/src/flutter.rs b/src/flutter.rs index 6c9ff7f37..8c4522e47 100644 --- a/src/flutter.rs +++ b/src/flutter.rs @@ -3,18 +3,19 @@ use crate::{ flutter_ffi::EventToUI, ui_session_interface::{io_loop, InvokeUiSession, Session}, }; -#[cfg(feature = "flutter_texture_render")] -use dlopen::{ - symbor::{Library, Symbol}, - Error as LibError, -}; use flutter_rust_bridge::StreamSink; -#[cfg(feature = "flutter_texture_render")] -use hbb_common::libc::c_void; use hbb_common::{ bail, config::LocalConfig, get_version_number, log, message_proto::*, rendezvous_proto::ConnType, ResultType, }; +#[cfg(feature = "flutter_texture_render")] +use hbb_common::{ + dlopen::{ + symbor::{Library, Symbol}, + Error as LibError, + }, + libc::c_void, +}; use serde_json::json; #[cfg(not(feature = "flutter_texture_render"))] diff --git a/src/server/video_service.rs b/src/server/video_service.rs index e6a4e3806..e5394157d 100644 --- a/src/server/video_service.rs +++ b/src/server/video_service.rs @@ -23,6 +23,8 @@ use super::{video_qos::VideoQoS, *}; use crate::platform::windows::is_process_consent_running; #[cfg(all(windows, feature = "privacy_win_mag"))] use crate::privacy_mode::privacy_win_mag; +#[cfg(all(windows, feature = "virtual_display_driver"))] +use hbb_common::config::LocalConfig; #[cfg(all(windows, feature = "privacy_win_mag"))] use hbb_common::get_version_number; use hbb_common::tokio::sync::{ @@ -48,6 +50,9 @@ use std::{ #[cfg(all(windows, feature = "virtual_display_driver"))] use virtual_display; +#[cfg(all(windows, feature = "virtual_display_driver"))] +const VIRTUAL_DISPLAY_INDEX_FOR_HEADLESS: u32 = 0; + pub const SCRAP_UBUNTU_HIGHER_REQUIRED: &str = "Wayland requires Ubuntu 21.04 or higher version."; pub const SCRAP_OTHER_VERSION_OR_X11_REQUIRED: &str = "Wayland requires higher version of linux distro. Please try X11 desktop or change your OS."; @@ -936,21 +941,20 @@ fn try_get_displays() -> ResultType> { if displays.len() == 0 { log::debug!("no displays, create virtual display"); // Try plugin monitor - if !virtual_display::is_device_created() { - if let Err(e) = virtual_display::create_device() { - log::debug!("Create device failed {}", e); - } - } - if virtual_display::is_device_created() { - if let Err(e) = virtual_display::plug_in_monitor() { - log::debug!("Plug in monitor failed {}", e); - } else { - if let Err(e) = virtual_display::update_monitor_modes() { - log::debug!("Update monitor modes failed {}", e); + if LocalConfig::get_virtual_display_num() > 0 { + if !virtual_display::is_device_created() { + if let Err(e) = virtual_display::create_device() { + log::debug!("Create device failed {}", e); } } + if virtual_display::is_device_created() { + if let Err(e) = virtual_display::plug_in_monitor(VIRTUAL_DISPLAY_INDEX_FOR_HEADLESS) + { + log::debug!("Plug in monitor failed {}", e); + } + } + displays = Display::all()?; } - displays = Display::all()?; } else if displays.len() > 1 { // to-do: do not close if in privacy mode. From 042a4e575f5c54ee4b7ca8f89a863862141062d0 Mon Sep 17 00:00:00 2001 From: fufesou Date: Mon, 17 Apr 2023 09:48:39 +0800 Subject: [PATCH 4/9] tmp commit Signed-off-by: fufesou --- libs/virtual_display/Cargo.toml | 2 +- .../dylib/src/win10/IddController.c | 4 +- src/lib.rs | 2 +- src/platform/windows.rs | 50 ++--- src/privacy_mode/mod.rs | 43 ---- src/privacy_mode/privacy_win_idd.rs | 188 ------------------ src/{privacy_mode => }/privacy_win_mag.rs | 8 +- src/server/connection.rs | 12 +- src/server/video_service.rs | 46 +++-- src/ui_cm_interface.rs | 4 +- 10 files changed, 67 insertions(+), 292 deletions(-) delete mode 100644 src/privacy_mode/mod.rs delete mode 100644 src/privacy_mode/privacy_win_idd.rs rename src/{privacy_mode => }/privacy_win_mag.rs (97%) diff --git a/libs/virtual_display/Cargo.toml b/libs/virtual_display/Cargo.toml index 2c2372212..2559ffbc0 100644 --- a/libs/virtual_display/Cargo.toml +++ b/libs/virtual_display/Cargo.toml @@ -7,4 +7,4 @@ edition = "2021" [dependencies] lazy_static = "1.4" -hbb_common = { path = "../hbb_common" } +hbb_common = { path = "../hbb_common" } \ No newline at end of file diff --git a/libs/virtual_display/dylib/src/win10/IddController.c b/libs/virtual_display/dylib/src/win10/IddController.c index c1faccfc2..6c240657a 100644 --- a/libs/virtual_display/dylib/src/win10/IddController.c +++ b/libs/virtual_display/dylib/src/win10/IddController.c @@ -196,7 +196,7 @@ BOOL DeviceCreate(PHSWDEVICE hSwDevice) } if (created == TRUE) { - SetLastMsg("Device is created before, please uninstall it first\n"); + SetLastMsg("Device is already created, please destroy it first\n"); if (g_printMsg) { printf(g_lastMsg); @@ -288,7 +288,7 @@ BOOL MonitorPlugIn(UINT index, UINT edid, INT retries) if (retries < 0) { - SetLastMsg("invalid tries %d\n", retries); + SetLastMsg("Invalid tries %d\n", retries); if (g_printMsg) { printf(g_lastMsg); diff --git a/src/lib.rs b/src/lib.rs index 7a7062b27..f52fbd1da 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -68,4 +68,4 @@ pub mod clipboard_file; pub mod rc; #[cfg(not(any(target_os = "android", target_os = "ios")))] -pub mod privacy_mode; +pub mod privacy_win_mag; diff --git a/src/platform/windows.rs b/src/platform/windows.rs index ab76c8559..b0b0d18e6 100644 --- a/src/platform/windows.rs +++ b/src/platform/windows.rs @@ -1,8 +1,10 @@ use super::{CursorData, ResultType}; use crate::common::PORTABLE_APPNAME_RUNTIME_ENV_KEY; -#[cfg(feature = "privacy_win_mag")] -use crate::privacy_mode::privacy_win_mag; -use crate::{ipc, license::*, privacy_mode::WIN_MAG_INJECTED_PROCESS_EXE}; +use crate::{ + ipc, + license::*, + privacy_win_mag::{self, WIN_MAG_INJECTED_PROCESS_EXE}, +}; use hbb_common::{ allow_err, bail, config::{self, Config}, @@ -10,12 +12,10 @@ use hbb_common::{ message_proto::Resolution, sleep, timeout, tokio, }; -#[cfg(feature = "privacy_win_mag")] -use std::fs; use std::{ collections::HashMap, ffi::OsString, - io, + fs, io, io::prelude::*, mem, os::windows::process::CommandExt, @@ -839,7 +839,6 @@ fn get_default_install_path() -> String { format!("{}\\{}", pf, crate::get_app_name()) } -#[cfg(feature = "privacy_win_mag")] pub fn check_update_broker_process() -> ResultType<()> { // let (_, path, _, _) = get_install_info(); let process_exe = privacy_win_mag::INJECTED_PROCESS_EXE; @@ -925,32 +924,17 @@ pub fn copy_raw_cmd(src_raw: &str, _raw: &str, _path: &str) -> String { pub fn copy_exe_cmd(src_exe: &str, exe: &str, path: &str) -> String { let main_exe = copy_raw_cmd(src_exe, exe, path); - - #[cfg(feature = "privacy_win_mag")] - { - format!( - " - {main_exe} - copy /Y \"{ORIGIN_PROCESS_EXE}\" \"{path}\\{broker_exe}\" - \"{src_exe}\" --extract \"{path}\" - ", - main_exe = main_exe, - path = path, - ORIGIN_PROCESS_EXE = privacy_win_mag::ORIGIN_PROCESS_EXE, - broker_exe = privacy_win_mag::INJECTED_PROCESS_EXE, - ) - } - #[cfg(not(feature = "privacy_win_mag"))] - { - format!( - " - {main_exe} - \"{src_exe}\" --extract \"{path}\" - ", - main_exe = main_exe, - path = path, - ) - } + format!( + " + {main_exe} + copy /Y \"{ORIGIN_PROCESS_EXE}\" \"{path}\\{broker_exe}\" + \"{src_exe}\" --extract \"{path}\" + ", + main_exe = main_exe, + path = path, + ORIGIN_PROCESS_EXE = privacy_win_mag::ORIGIN_PROCESS_EXE, + broker_exe = privacy_win_mag::INJECTED_PROCESS_EXE, + ) } pub fn update_me() -> ResultType<()> { diff --git a/src/privacy_mode/mod.rs b/src/privacy_mode/mod.rs deleted file mode 100644 index 9b21177f8..000000000 --- a/src/privacy_mode/mod.rs +++ /dev/null @@ -1,43 +0,0 @@ -use crate::ipc::PrivacyModeState; -use hbb_common::{bail, ResultType}; - -#[cfg(all(windows, feature = "privacy_win_mag"))] -pub mod privacy_win_mag; -pub const WIN_MAG_INJECTED_PROCESS_EXE: &'static str = "RuntimeBroker_rustdesk.exe"; - -pub const OCCUPIED: &'static str = "Privacy occupied by another one"; -pub const TURN_OFF_OTHER_ID: &'static str = - "Failed to turn off privacy mode that belongs to someone else"; -pub const NO_DISPLAYS: &'static str = "No displays"; - -#[cfg(all(windows, feature = "virtual_display_driver"))] -pub mod privacy_win_idd; - -pub trait PrivacyMode { - fn turn_on_privacy(&mut self, conn_id: i32) -> ResultType; - fn turn_off_privacy(&mut self, conn_id: i32, state: Option) - -> ResultType<()>; - - fn cur_conn_id(&self) -> i32; - - #[inline] - fn check_on_conn_id(&self, conn_id: i32) -> ResultType { - let pre_conn_id = self.cur_conn_id(); - if pre_conn_id == conn_id { - return Ok(true); - } - if pre_conn_id != 0 { - bail!(OCCUPIED); - } - Ok(false) - } - - #[inline] - fn check_off_conn_id(&self, conn_id: i32) -> ResultType<()> { - let pre_conn_id = self.cur_conn_id(); - if pre_conn_id != 0 && conn_id != 0 && pre_conn_id != conn_id { - bail!(TURN_OFF_OTHER_ID) - } - Ok(()) - } -} diff --git a/src/privacy_mode/privacy_win_idd.rs b/src/privacy_mode/privacy_win_idd.rs deleted file mode 100644 index 13798bf16..000000000 --- a/src/privacy_mode/privacy_win_idd.rs +++ /dev/null @@ -1,188 +0,0 @@ -use super::{PrivacyModeState, NO_DISPLAYS}; -use hbb_common::{allow_err, bail, lazy_static, log, ResultType}; -use scrap::dxgi; -use winapi::{ - shared::{ - minwindef::{DWORD, FALSE}, - ntdef::{NULL, WCHAR}, - }, - um::{ - errhandlingapi::GetLastError, - wingdi::{DEVMODEW, DISPLAY_DEVICEW, DISPLAY_DEVICE_ATTACHED_TO_DESKTOP, DM_POSITION}, - winuser::{ - ChangeDisplaySettingsExW, EnumDisplayDevicesW, EnumDisplaySettingsW, CDS_NORESET, - CDS_SET_PRIMARY, CDS_UPDATEREGISTRY, DISP_CHANGE_SUCCESSFUL, - EDD_GET_DEVICE_INTERFACE_NAME, ENUM_CURRENT_SETTINGS, - }, - }, -}; - -const IDD_DEVICE_STRING: &'static str = "RustDeskIddDriver Device"; - -struct Display { - dm: DEVMODEW, - name: [WCHAR; 32], - primary: bool, -} - -pub struct PrivacyModeImpl { - conn_id: i32, - displays: Vec, - virtual_displays: Vec, - virtual_displays_added: Option, -} - -impl PrivacyModeImpl { - fn set_displays(&mut self) { - self.displays.clear(); - self.virtual_displays.clear(); - for display in dxgi::Displays::get_from_gdi().into_iter() { - if let Some(gdi_info) = display.gdi() { - if let Ok(s) = std::string::String::from_utf16(&gdi_info.dd.DeviceString) { - if s == IDD_DEVICE_STRING { - self.virtual_displays.push(Display { - dm: gdi_info.dm, - name: gdi_info.dd.DeviceName, - primary: gdi_info.is_primary, - }); - continue; - } - } - self.displays.push(Display { - dm: gdi_info.dm, - name: gdi_info.dd.DeviceName, - primary: gdi_info.is_primary, - }); - } - } - } - - fn restore(&self) {} - - fn set_primary_display(&mut self) -> ResultType<()> { - self.ensure_virtual_display()?; - if self.virtual_displays.is_empty() { - bail!("No virtual displays"); - } - let display = &self.virtual_displays[0]; - - let mut new_primary_dm: DEVMODEW = unsafe { std::mem::MaybeUninit::uninit().assume_init() }; - new_primary_dm.dmSize = std::mem::size_of::() as _; - new_primary_dm.dmDriverExtra = 0; - unsafe { - if FALSE - == EnumDisplaySettingsW( - display.name.as_ptr(), - ENUM_CURRENT_SETTINGS, - &mut new_primary_dm, - ) - { - bail!( - "Failed EnumDisplaySettingsW, device name: {:?}, error code: {}", - std::string::String::from_utf16(&display.name), - GetLastError() - ); - } - - let mut i: DWORD = 0; - loop { - let mut flags = CDS_UPDATEREGISTRY | CDS_NORESET; - let mut dd: DISPLAY_DEVICEW = std::mem::MaybeUninit::uninit().assume_init(); - dd.cb = std::mem::size_of::() as _; - if FALSE - == EnumDisplayDevicesW(NULL as _, i, &mut dd, EDD_GET_DEVICE_INTERFACE_NAME) - { - break; - } - i += 1; - if (dd.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP) == 0 { - continue; - } - - if dd.DeviceName == display.name { - flags |= CDS_SET_PRIMARY; - } - - let mut dm: DEVMODEW = std::mem::MaybeUninit::uninit().assume_init(); - dm.dmSize = std::mem::size_of::() as _; - dm.dmDriverExtra = 0; - if FALSE - == EnumDisplaySettingsW(dd.DeviceName.as_ptr(), ENUM_CURRENT_SETTINGS, &mut dm) - { - bail!( - "Failed EnumDisplaySettingsW, device name: {:?}, error code: {}", - std::string::String::from_utf16(&dd.DeviceName), - GetLastError() - ); - } - - dm.u1.s2_mut().dmPosition.x -= new_primary_dm.u1.s2().dmPosition.x; - dm.u1.s2_mut().dmPosition.y -= new_primary_dm.u1.s2().dmPosition.y; - dm.dmFields |= DM_POSITION; - let rc = ChangeDisplaySettingsExW( - dd.DeviceName.as_ptr(), - &mut dm, - NULL as _, - flags, - NULL, - ); - - if rc != DISP_CHANGE_SUCCESSFUL { - log::error!( - "Failed ChangeDisplaySettingsEx, device name: {:?}, flags: {}, ret: {}", - std::string::String::from_utf16(&dd.DeviceName), - flags, - rc - ); - bail!("Failed ChangeDisplaySettingsEx, ret: {}", rc); - } - } - } - - Ok(()) - } - - fn ensure_virtual_display(&mut self) -> ResultType<()> { - if self.virtual_displays.is_empty() { - virtual_display::create_device()?; - } - if virtual_display::is_device_created() { - // to-do: add monitor index here - virtual_display::plug_in_monitor()?; - self.virtual_displays_added = Some(0); - } - - self.set_displays(); - Ok(()) - } -} - -impl super::PrivacyMode for PrivacyModeImpl { - fn turn_on_privacy(&mut self, conn_id: i32) -> ResultType { - if self.check_on_conn_id(conn_id)? { - return Ok(true); - } - self.set_displays(); - if self.displays.is_empty() { - bail!(NO_DISPLAYS); - } - self.set_primary_display()?; - - bail!("unimplemented") - } - - fn turn_off_privacy( - &mut self, - conn_id: i32, - state: Option, - ) -> ResultType<()> { - self.check_off_conn_id(conn_id)?; - self.restore(); - bail!("unimplemented") - } - - #[inline] - fn cur_conn_id(&self) -> i32 { - self.conn_id - } -} diff --git a/src/privacy_mode/privacy_win_mag.rs b/src/privacy_win_mag.rs similarity index 97% rename from src/privacy_mode/privacy_win_mag.rs rename to src/privacy_win_mag.rs index 923c42859..fe0ee4f69 100644 --- a/src/privacy_mode/privacy_win_mag.rs +++ b/src/privacy_win_mag.rs @@ -31,9 +31,15 @@ use winapi::{ }; pub const ORIGIN_PROCESS_EXE: &'static str = "C:\\Windows\\System32\\RuntimeBroker.exe"; -pub const INJECTED_PROCESS_EXE: &'static str = super::WIN_MAG_INJECTED_PROCESS_EXE; +pub const WIN_MAG_INJECTED_PROCESS_EXE: &'static str = "RuntimeBroker_rustdesk.exe"; +pub const INJECTED_PROCESS_EXE: &'static str = WIN_MAG_INJECTED_PROCESS_EXE; pub const PRIVACY_WINDOW_NAME: &'static str = "RustDeskPrivacyWindow"; +pub const OCCUPIED: &'static str = "Privacy occupied by another one"; +pub const TURN_OFF_OTHER_ID: &'static str = + "Failed to turn off privacy mode that belongs to someone else"; +pub const NO_DISPLAYS: &'static str = "No displays"; + pub const GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT: u32 = 2; pub const GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS: u32 = 4; diff --git a/src/server/connection.rs b/src/server/connection.rs index 25dea58ad..d4b645078 100644 --- a/src/server/connection.rs +++ b/src/server/connection.rs @@ -2346,11 +2346,11 @@ fn try_activate_screen() { mod privacy_mode { use super::*; - #[cfg(all(windows, feature = "privacy_win_mag"))] - use crate::privacy_mode::privacy_win_mag; + #[cfg(windows)] + use crate::privacy_win_mag; pub(super) fn turn_off_privacy(_conn_id: i32) -> Message { - #[cfg(all(windows, feature = "privacy_win_mag"))] + #[cfg(windows)] { let res = privacy_win_mag::turn_off_privacy(_conn_id, None); match res { @@ -2365,19 +2365,19 @@ mod privacy_mode { } } } - #[cfg(not(all(windows, feature = "privacy_win_mag")))] + #[cfg(not(windows))] { crate::common::make_privacy_mode_msg(back_notification::PrivacyModeState::PrvOffFailed) } } pub(super) fn turn_on_privacy(_conn_id: i32) -> ResultType { - #[cfg(all(windows, feature = "privacy_win_mag"))] + #[cfg(windows)] { let plugin_exist = privacy_win_mag::turn_on_privacy(_conn_id)?; Ok(plugin_exist) } - #[cfg(not(all(windows, feature = "privacy_win_mag")))] + #[cfg(not(windows))] { Ok(true) } diff --git a/src/server/video_service.rs b/src/server/video_service.rs index e5394157d..4789d4fd6 100644 --- a/src/server/video_service.rs +++ b/src/server/video_service.rs @@ -20,12 +20,10 @@ use super::{video_qos::VideoQoS, *}; #[cfg(windows)] -use crate::platform::windows::is_process_consent_running; -#[cfg(all(windows, feature = "privacy_win_mag"))] -use crate::privacy_mode::privacy_win_mag; +use crate::{platform::windows::is_process_consent_running, privacy_win_mag}; #[cfg(all(windows, feature = "virtual_display_driver"))] use hbb_common::config::LocalConfig; -#[cfg(all(windows, feature = "privacy_win_mag"))] +#[cfg(windows)] use hbb_common::get_version_number; use hbb_common::tokio::sync::{ mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender}, @@ -78,9 +76,9 @@ lazy_static::lazy_static! { } fn is_capturer_mag_supported() -> bool { - #[cfg(all(windows, feature = "privacy_win_mag"))] + #[cfg(windows)] return scrap::CapturerMag::is_supported(); - #[cfg(not(all(windows, feature = "privacy_win_mag")))] + #[cfg(not(windows))] false } @@ -101,10 +99,10 @@ pub fn get_privacy_mode_conn_id() -> i32 { } pub fn is_privacy_mode_supported() -> bool { - #[cfg(all(windows, feature = "privacy_win_mag"))] + #[cfg(windows)] return *IS_CAPTURER_MAGNIFIER_SUPPORTED && get_version_number(&crate::VERSION) > get_version_number("1.1.9"); - #[cfg(not(all(windows, feature = "privacy_win_mag")))] + #[cfg(not(windows))] return false; } @@ -210,12 +208,12 @@ fn create_capturer( _current: usize, _portable_service_running: bool, ) -> ResultType> { - #[cfg(not(all(windows, feature = "privacy_win_mag")))] + #[cfg(not(windows))] let c: Option> = None; - #[cfg(all(windows, feature = "privacy_win_mag"))] + #[cfg(windows)] let mut c: Option> = None; if privacy_mode_id > 0 { - #[cfg(all(windows, feature = "privacy_win_mag"))] + #[cfg(windows)] { match scrap::CapturerMag::new( display.origin(), @@ -942,21 +940,39 @@ fn try_get_displays() -> ResultType> { log::debug!("no displays, create virtual display"); // Try plugin monitor if LocalConfig::get_virtual_display_num() > 0 { - if !virtual_display::is_device_created() { - if let Err(e) = virtual_display::create_device() { + let mut device_already_created = false; + if let Err(e) = virtual_display::create_device() { + if e.to_string().contains("Device is already created") { + device_already_created = true; + } else { log::debug!("Create device failed {}", e); } } - if virtual_display::is_device_created() { + if device_already_created || virtual_display::is_device_created() { + // Reboot is not required for this case. + let mut _reboot_required = false; + virtual_display::install_update_driver(&mut _reboot_required)?; if let Err(e) = virtual_display::plug_in_monitor(VIRTUAL_DISPLAY_INDEX_FOR_HEADLESS) { log::debug!("Plug in monitor failed {}", e); + } else { + let modes = [virtual_display::MonitorMode { + width: 1920, + height: 1080, + sync: 60, + }]; + if let Err(e) = virtual_display::update_monitor_modes( + VIRTUAL_DISPLAY_INDEX_FOR_HEADLESS, + &modes, + ) { + log::debug!("Update monitor modes failed {}", e); + } } } displays = Display::all()?; } } else if displays.len() > 1 { - // to-do: do not close if in privacy mode. + // to-do: do not close if in idd privacy mode. // If more than one displays exists, close RustDeskVirtualDisplay if virtual_display::is_device_created() { diff --git a/src/ui_cm_interface.rs b/src/ui_cm_interface.rs index b738bd4ac..b6bb3e35d 100644 --- a/src/ui_cm_interface.rs +++ b/src/ui_cm_interface.rs @@ -495,7 +495,7 @@ impl IpcTaskRunner { #[cfg(not(any(target_os = "android", target_os = "ios")))] #[tokio::main(flavor = "current_thread")] pub async fn start_ipc(cm: ConnectionManager) { - #[cfg(all(windows, feature = "privacy_win_mag"))] + #[cfg(windows)] std::thread::spawn(move || { log::info!("try create privacy mode window"); if let Err(e) = crate::platform::windows::check_update_broker_process() { @@ -504,7 +504,7 @@ pub async fn start_ipc(cm: ConnectionManager) { e ); } - allow_err!(crate::privacy_mode::privacy_win_mag::start()); + allow_err!(crate::privacy_win_mag::start()); }); match ipc::new_listener("_cm").await { From 9d8e7745e2b8977a60b5c48c620441d8144b44ce Mon Sep 17 00:00:00 2001 From: fufesou Date: Mon, 17 Apr 2023 12:05:36 +0800 Subject: [PATCH 5/9] refact virtual display Signed-off-by: fufesou --- build.py | 4 +- libs/hbb_common/src/config.rs | 15 --- .../examples/virtual_display_1.rs | 4 +- libs/virtual_display/src/lib.rs | 5 +- src/lib.rs | 3 + src/server/video_service.rs | 60 ++-------- src/virtual_display_manager.rs | 106 ++++++++++++++++++ 7 files changed, 125 insertions(+), 72 deletions(-) create mode 100644 src/virtual_display_manager.rs diff --git a/build.py b/build.py index fb9e213db..cc00c0793 100755 --- a/build.py +++ b/build.py @@ -41,8 +41,8 @@ def get_version(): def parse_rc_features(feature): available_features = { 'IddDriver': { - 'zip_url': 'https://github.com/fufesou/RustDeskIddDriver/releases/download/v0.1/RustDeskIddDriver_x64.zip', - 'checksum_url': 'https://github.com/fufesou/RustDeskIddDriver/releases/download/v0.1/checksum_md5', + 'zip_url': 'https://github.com/fufesou/RustDeskIddDriver/releases/download/v0.3/RustDeskIddDriver_x64.zip', + 'checksum_url': 'https://github.com/fufesou/RustDeskIddDriver/releases/download/v0.3/checksum_md5', 'exclude': ['README.md', 'certmgr.exe', 'install_cert_runas_admin.bat'], }, 'PrivacyMode': { diff --git a/libs/hbb_common/src/config.rs b/libs/hbb_common/src/config.rs index 8786858e2..369920982 100644 --- a/libs/hbb_common/src/config.rs +++ b/libs/hbb_common/src/config.rs @@ -1141,8 +1141,6 @@ pub struct LocalConfig { // Various data for flutter ui #[serde(default)] ui_flutter: HashMap, - #[serde(default)] - virtual_display_num: usize, } impl LocalConfig { @@ -1245,19 +1243,6 @@ impl LocalConfig { config.store(); } } - - pub fn get_virtual_display_num() -> usize { - LOCAL_CONFIG.read().unwrap().virtual_display_num - } - - pub fn set_virtual_display_num(virtual_display_num: usize) { - let mut lock = LOCAL_CONFIG.write().unwrap(); - if lock.virtual_display_num == virtual_display_num { - return; - } - lock.virtual_display_num = virtual_display_num; - lock.store(); - } } #[derive(Debug, Default, Serialize, Deserialize, Clone)] diff --git a/libs/virtual_display/examples/virtual_display_1.rs b/libs/virtual_display/examples/virtual_display_1.rs index 1471e3faf..e5e1ae554 100644 --- a/libs/virtual_display/examples/virtual_display_1.rs +++ b/libs/virtual_display/examples/virtual_display_1.rs @@ -3,7 +3,7 @@ use virtual_display; fn prompt_input() -> u8 { println!("Press key execute:"); - println!(" 1. 'x' 1. exit"); + println!(" 1. 'q' 1. quit"); println!(" 2. 'i' 2. install or update driver"); println!(" 3. 'u' 3. uninstall driver"); println!(" 4. 'c' 4. create device"); @@ -40,7 +40,7 @@ fn main() { loop { let chr = prompt_input(); match chr as char { - 'x' => break, + 'q' => break, 'i' => { println!("Install or update driver begin"); let mut reboot_required = false; diff --git a/libs/virtual_display/src/lib.rs b/libs/virtual_display/src/lib.rs index f7e904537..578ffa2e9 100644 --- a/libs/virtual_display/src/lib.rs +++ b/libs/virtual_display/src/lib.rs @@ -47,7 +47,10 @@ macro_rules! make_lib_wrapper { $(let $field = if let Some(lib) = &lib { match unsafe { lib.symbol::<$tp>(stringify!($field)) } { - Ok(m) => Some(*m), + Ok(m) => { + log::info!("method found {}", stringify!($field)); + Some(*m) + }, Err(e) => { log::warn!("Failed to load func {}, {}", stringify!($field), e); None diff --git a/src/lib.rs b/src/lib.rs index f52fbd1da..52e9fcd5d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -69,3 +69,6 @@ pub mod rc; #[cfg(not(any(target_os = "android", target_os = "ios")))] pub mod privacy_win_mag; + +#[cfg(all(windows, feature = "virtual_display_driver"))] +pub mod virtual_display_manager; diff --git a/src/server/video_service.rs b/src/server/video_service.rs index 4789d4fd6..e6f29a405 100644 --- a/src/server/video_service.rs +++ b/src/server/video_service.rs @@ -19,10 +19,10 @@ // https://slhck.info/video/2017/03/01/rate-control.html use super::{video_qos::VideoQoS, *}; +#[cfg(all(windows, feature = "virtual_display_driver"))] +use crate::virtual_display_manager; #[cfg(windows)] use crate::{platform::windows::is_process_consent_running, privacy_win_mag}; -#[cfg(all(windows, feature = "virtual_display_driver"))] -use hbb_common::config::LocalConfig; #[cfg(windows)] use hbb_common::get_version_number; use hbb_common::tokio::sync::{ @@ -45,11 +45,6 @@ use std::{ ops::{Deref, DerefMut}, time::{self, Duration, Instant}, }; -#[cfg(all(windows, feature = "virtual_display_driver"))] -use virtual_display; - -#[cfg(all(windows, feature = "virtual_display_driver"))] -const VIRTUAL_DISPLAY_INDEX_FOR_HEADLESS: u32 = 0; pub const SCRAP_UBUNTU_HIGHER_REQUIRED: &str = "Wayland requires Ubuntu 21.04 or higher version."; pub const SCRAP_OTHER_VERSION_OR_X11_REQUIRED: &str = @@ -284,15 +279,8 @@ fn create_capturer( #[cfg(all(windows, feature = "virtual_display_driver"))] fn ensure_close_virtual_device() -> ResultType<()> { let num_displays = Display::all()?.len(); - if num_displays == 0 { - // Device may sometimes be uninstalled by user in "Device Manager" Window. - // Closing device will clear the instance data. - virtual_display::close_device(); - } else if num_displays > 1 { - // Try close device, if display device changed. - if virtual_display::is_device_created() { - virtual_display::close_device(); - } + if num_displays > 1 { + virtual_display_manager::plug_out_headless(); } Ok(()) } @@ -938,46 +926,14 @@ fn try_get_displays() -> ResultType> { let mut displays = Display::all()?; if displays.len() == 0 { log::debug!("no displays, create virtual display"); - // Try plugin monitor - if LocalConfig::get_virtual_display_num() > 0 { - let mut device_already_created = false; - if let Err(e) = virtual_display::create_device() { - if e.to_string().contains("Device is already created") { - device_already_created = true; - } else { - log::debug!("Create device failed {}", e); - } - } - if device_already_created || virtual_display::is_device_created() { - // Reboot is not required for this case. - let mut _reboot_required = false; - virtual_display::install_update_driver(&mut _reboot_required)?; - if let Err(e) = virtual_display::plug_in_monitor(VIRTUAL_DISPLAY_INDEX_FOR_HEADLESS) - { - log::debug!("Plug in monitor failed {}", e); - } else { - let modes = [virtual_display::MonitorMode { - width: 1920, - height: 1080, - sync: 60, - }]; - if let Err(e) = virtual_display::update_monitor_modes( - VIRTUAL_DISPLAY_INDEX_FOR_HEADLESS, - &modes, - ) { - log::debug!("Update monitor modes failed {}", e); - } - } - } + if let Err(e) = virtual_display_manager::plug_in_headless() { + log::error!("plug in headless failed {}", e); + } else { displays = Display::all()?; } } else if displays.len() > 1 { - // to-do: do not close if in idd privacy mode. - // If more than one displays exists, close RustDeskVirtualDisplay - if virtual_display::is_device_created() { - virtual_display::close_device() - } + let _res = virtual_display_manager::plug_in_headless(); } Ok(displays) } diff --git a/src/virtual_display_manager.rs b/src/virtual_display_manager.rs new file mode 100644 index 000000000..82328915e --- /dev/null +++ b/src/virtual_display_manager.rs @@ -0,0 +1,106 @@ +use hbb_common::{allow_err, bail, lazy_static, log, ResultType}; +use std::{ + collections::HashSet, + sync::{Arc, Mutex}, +}; + +// virtual display index range: 0 - 2 are reserved for headless and other special uses. +const VIRTUAL_DISPLAY_INDEX_FOR_HEADLESS: u32 = 0; +const VIRTUAL_DISPLAY_START_FOR_PEER: u32 = 3; +const VIRTUAL_DISPLAY_MAX_COUNT: u32 = 10; + +lazy_static::lazy_static! { + static ref VIRTUAL_DISPLAY_MANAGER: Arc> = + Arc::new(Mutex::new(VirtualDisplayManager::default())); +} + +#[derive(Default)] +struct VirtualDisplayManager { + headless_index: Option, + peer_required_indices: HashSet, +} + +impl VirtualDisplayManager { + fn prepare_driver() -> ResultType<()> { + if let Err(e) = virtual_display::create_device() { + if !e.to_string().contains("Device is already created") { + bail!("Create device failed {}", e); + } + } + // Reboot is not required for this case. + let mut _reboot_required = false; + allow_err!(virtual_display::install_update_driver( + &mut _reboot_required + )); + Ok(()) + } + + fn plug_in_monitor(index: u32, modes: &[virtual_display::MonitorMode]) -> ResultType<()> { + if let Err(e) = virtual_display::plug_in_monitor(index) { + bail!("Plug in monitor failed {}", e); + } + if let Err(e) = virtual_display::update_monitor_modes(index, &modes) { + log::error!("Update monitor modes failed {}", e); + } + Ok(()) + } +} + +pub fn plug_in_headless() -> ResultType<()> { + let mut manager = VIRTUAL_DISPLAY_MANAGER.lock().unwrap(); + VirtualDisplayManager::prepare_driver()?; + let modes = [virtual_display::MonitorMode { + width: 1920, + height: 1080, + sync: 60, + }]; + VirtualDisplayManager::plug_in_monitor(VIRTUAL_DISPLAY_INDEX_FOR_HEADLESS, &modes)?; + manager.headless_index = Some(VIRTUAL_DISPLAY_INDEX_FOR_HEADLESS); + Ok(()) +} + +pub fn plug_out_headless() { + let mut manager = VIRTUAL_DISPLAY_MANAGER.lock().unwrap(); + if let Some(index) = manager.headless_index.take() { + if let Err(e) = virtual_display::plug_out_monitor(index) { + log::error!("Plug out monitor failed {}", e); + } + } +} + +pub fn plug_in_peer_required( + modes: Vec>, +) -> ResultType> { + let mut manager = VIRTUAL_DISPLAY_MANAGER.lock().unwrap(); + VirtualDisplayManager::prepare_driver()?; + + let mut indices: Vec = Vec::new(); + for m in modes.iter() { + for idx in VIRTUAL_DISPLAY_START_FOR_PEER..VIRTUAL_DISPLAY_MAX_COUNT { + if !manager.peer_required_indices.contains(&idx) { + match VirtualDisplayManager::plug_in_monitor(idx, m) { + Ok(_) => { + manager.peer_required_indices.insert(idx); + indices.push(idx); + } + Err(e) => { + log::error!("Plug in monitor failed {}", e); + } + } + } + } + } + + Ok(indices) +} + +pub fn plug_out_peer_required(modes: &[u32]) -> ResultType<()> { + let mut manager = VIRTUAL_DISPLAY_MANAGER.lock().unwrap(); + for idx in modes.iter() { + if manager.peer_required_indices.contains(idx) { + allow_err!(virtual_display::plug_out_monitor(*idx)); + manager.peer_required_indices.remove(idx); + } + } + Ok(()) +} From 8f7b4b198d92255e360b2fc63c0f4b00fecdcddf Mon Sep 17 00:00:00 2001 From: fufesou Date: Mon, 17 Apr 2023 12:10:38 +0800 Subject: [PATCH 6/9] enable virtual_display_driver on win Signed-off-by: fufesou --- build.py | 1 + 1 file changed, 1 insertion(+) diff --git a/build.py b/build.py index cc00c0793..053d59c47 100755 --- a/build.py +++ b/build.py @@ -242,6 +242,7 @@ def get_features(args): features = ['inline'] if not args.flutter else [] if windows: features.extend(get_rc_features(args)) + features.append('virtual_display_driver') if args.hwcodec: features.append('hwcodec') if args.flutter: From 4d6358f1c87e8d2e49d920c11aed500449309d62 Mon Sep 17 00:00:00 2001 From: fufesou Date: Mon, 17 Apr 2023 12:16:16 +0800 Subject: [PATCH 7/9] revert scrap dxgi mode.rs Signed-off-by: fufesou --- libs/scrap/src/dxgi/mod.rs | 80 ++++++++++++++------------------------ 1 file changed, 29 insertions(+), 51 deletions(-) diff --git a/libs/scrap/src/dxgi/mod.rs b/libs/scrap/src/dxgi/mod.rs index 2d9bd636f..547f18987 100644 --- a/libs/scrap/src/dxgi/mod.rs +++ b/libs/scrap/src/dxgi/mod.rs @@ -62,7 +62,7 @@ impl Capturer { let mut desc = unsafe { mem::MaybeUninit::uninit().assume_init() }; let mut gdi_capturer = None; - let mut res = if display.gdi.is_some() { + let mut res = if display.gdi { wrap_hresult(1) } else { wrap_hresult(unsafe { @@ -367,60 +367,48 @@ impl Displays { let mut i: DWORD = 0; loop { #[allow(invalid_value)] - let mut dd: DISPLAY_DEVICEW = unsafe { std::mem::MaybeUninit::uninit().assume_init() }; - dd.cb = std::mem::size_of::() as _; - let ok = unsafe { EnumDisplayDevicesW(std::ptr::null(), i, &mut dd as _, 0) }; + let mut d: DISPLAY_DEVICEW = unsafe { std::mem::MaybeUninit::uninit().assume_init() }; + d.cb = std::mem::size_of::() as _; + let ok = unsafe { EnumDisplayDevicesW(std::ptr::null(), i, &mut d as _, 0) }; if ok == FALSE { break; } i += 1; - if 0 == (dd.StateFlags & DISPLAY_DEVICE_ACTIVE) - || (dd.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) > 0 + if 0 == (d.StateFlags & DISPLAY_DEVICE_ACTIVE) + || (d.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) > 0 { continue; } + // let is_primary = (d.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) > 0; let mut disp = Display { inner: ComPtr(std::ptr::null_mut()), adapter: ComPtr(std::ptr::null_mut()), desc: unsafe { std::mem::zeroed() }, - gdi: None, + gdi: true, }; - disp.desc.DeviceName = dd.DeviceName.clone(); + disp.desc.DeviceName = d.DeviceName; #[allow(invalid_value)] - let mut dm: DEVMODEW = unsafe { std::mem::MaybeUninit::uninit().assume_init() }; - dm.dmSize = std::mem::size_of::() as _; - dm.dmDriverExtra = 0; - unsafe { - if FALSE - == EnumDisplaySettingsExW( - disp.desc.DeviceName.as_ptr(), - ENUM_CURRENT_SETTINGS, - &mut dm as _, - 0, - ) - { - if FALSE - == EnumDisplaySettingsExW( - disp.desc.DeviceName.as_ptr(), - ENUM_REGISTRY_SETTINGS, - &mut dm as _, - 0, - ) - { - continue; - } - } + let mut m: DEVMODEW = unsafe { std::mem::MaybeUninit::uninit().assume_init() }; + m.dmSize = std::mem::size_of::() as _; + m.dmDriverExtra = 0; + let ok = unsafe { + EnumDisplaySettingsExW( + disp.desc.DeviceName.as_ptr(), + ENUM_CURRENT_SETTINGS, + &mut m as _, + 0, + ) + }; + if ok == FALSE { + continue; } - disp.desc.DesktopCoordinates.left = unsafe { dm.u1.s2().dmPosition.x }; - disp.desc.DesktopCoordinates.top = unsafe { dm.u1.s2().dmPosition.y }; + disp.desc.DesktopCoordinates.left = unsafe { m.u1.s2().dmPosition.x }; + disp.desc.DesktopCoordinates.top = unsafe { m.u1.s2().dmPosition.y }; disp.desc.DesktopCoordinates.right = - disp.desc.DesktopCoordinates.left + dm.dmPelsWidth as i32; + disp.desc.DesktopCoordinates.left + m.dmPelsWidth as i32; disp.desc.DesktopCoordinates.bottom = - disp.desc.DesktopCoordinates.top + dm.dmPelsHeight as i32; + disp.desc.DesktopCoordinates.top + m.dmPelsHeight as i32; disp.desc.AttachedToDesktop = 1; - - let is_primary = (dd.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) > 0; - disp.gdi = Some(GdiDisplayInfo { dd, dm, is_primary }); all.push(disp); } all @@ -488,7 +476,7 @@ impl Displays { inner: ComPtr(inner), adapter: ComPtr(self.adapter.0), desc, - gdi: None, + gdi: false, })) } } @@ -524,13 +512,7 @@ pub struct Display { inner: ComPtr, adapter: ComPtr, desc: DXGI_OUTPUT_DESC, - gdi: Option, -} - -pub struct GdiDisplayInfo { - pub dd: DISPLAY_DEVICEW, - pub dm: DEVMODEW, - pub is_primary: bool, + gdi: bool, } // optimized for updated region @@ -555,10 +537,6 @@ impl Display { self.desc.Rotation } - pub fn gdi(&self) -> &Option { - &self.gdi - } - fn create_gdi(&self) -> Option { if let Ok(res) = CapturerGDI::new(self.name(), self.width(), self.height()) { Some(res) @@ -607,4 +585,4 @@ fn wrap_hresult(x: HRESULT) -> io::Result<()> { } }) .into()) -} +} \ No newline at end of file From 67d29e749679879f50344216ab88b4d9a55e2068 Mon Sep 17 00:00:00 2001 From: fufesou Date: Mon, 17 Apr 2023 12:17:31 +0800 Subject: [PATCH 8/9] trivail change Signed-off-by: fufesou --- libs/scrap/src/dxgi/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/scrap/src/dxgi/mod.rs b/libs/scrap/src/dxgi/mod.rs index 547f18987..4a0a53402 100644 --- a/libs/scrap/src/dxgi/mod.rs +++ b/libs/scrap/src/dxgi/mod.rs @@ -585,4 +585,4 @@ fn wrap_hresult(x: HRESULT) -> io::Result<()> { } }) .into()) -} \ No newline at end of file +} From b7af404afa6b240441c6805185b672b6fad1db13 Mon Sep 17 00:00:00 2001 From: fufesou Date: Mon, 17 Apr 2023 13:01:38 +0800 Subject: [PATCH 9/9] fix build Signed-off-by: fufesou --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 52e9fcd5d..d5f791eeb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -67,7 +67,7 @@ pub mod clipboard_file; #[cfg(all(windows, feature = "with_rc"))] pub mod rc; -#[cfg(not(any(target_os = "android", target_os = "ios")))] +#[cfg(windows)] pub mod privacy_win_mag; #[cfg(all(windows, feature = "virtual_display_driver"))]