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 {