From 117bbb340919db19593113433c5e0bca3c86167f Mon Sep 17 00:00:00 2001 From: fufesou Date: Tue, 15 Mar 2022 00:29:07 +0800 Subject: [PATCH] virtual display: plugout monitor on disconnecting, debug failed, may crash... Signed-off-by: fufesou --- libs/virtual_display/Cargo.toml | 2 +- libs/virtual_display/README.md | 4 +- libs/virtual_display/src/lib.rs | 61 ++++++++++++++++--- src/server/video_service.rs | 104 ++++++++++++-------------------- 4 files changed, 92 insertions(+), 79 deletions(-) diff --git a/libs/virtual_display/Cargo.toml b/libs/virtual_display/Cargo.toml index 0f7535d46..8d0b65171 100644 --- a/libs/virtual_display/Cargo.toml +++ b/libs/virtual_display/Cargo.toml @@ -13,4 +13,4 @@ thiserror = "1.0.30" lazy_static = "1.4" serde = "1.0" serde_derive = "1.0" -hbb_common = { path = "../hbb_common" } \ No newline at end of file +hbb_common = { path = "../hbb_common" } diff --git a/libs/virtual_display/README.md b/libs/virtual_display/README.md index dbc4ac6bd..d5a1a0862 100644 --- a/libs/virtual_display/README.md +++ b/libs/virtual_display/README.md @@ -10,7 +10,7 @@ Virtual display may be used on computers that do not have a monitor. Win10 provides [Indirect Display Driver Model](https://msdn.microsoft.com/en-us/library/windows/hardware/mt761968(v=vs.85).aspx). -This lib use [this project](https://github.com/fufesou/RustDeskIddDriver) as the driver. +This lib uses [this project](https://github.com/fufesou/RustDeskIddDriver) as the driver. **NOTE**: Versions before Win10 1607. Try follow [this method](https://github.com/fanxiushu/xdisp_virt/tree/master/indirect_display). @@ -19,7 +19,7 @@ This lib use [this project](https://github.com/fufesou/RustDeskIddDriver) as the #### tested platforms - [x] 19041 - +- [x] 19043 ### win7 diff --git a/libs/virtual_display/src/lib.rs b/libs/virtual_display/src/lib.rs index e9dc32fe7..237e2cf15 100644 --- a/libs/virtual_display/src/lib.rs +++ b/libs/virtual_display/src/lib.rs @@ -6,6 +6,7 @@ use std::{ffi::CString, path::Path, sync::Mutex}; lazy_static::lazy_static! { static ref H_SW_DEVICE: Mutex = Mutex::new(0); + static ref MONITOR_PLUGIN: Mutex> = Mutex::new(Vec::new()); } pub fn download_driver() -> ResultType<()> { @@ -90,46 +91,88 @@ pub fn is_device_created() -> bool { return false; } -#[cfg(windows)] pub fn create_device() -> ResultType<()> { if is_device_created() { return Ok(()); } + #[cfg(windows)] unsafe { let mut h_sw_device = *H_SW_DEVICE.lock().unwrap() as win10::idd::HSWDEVICE; if win10::idd::DeviceCreate(&mut h_sw_device) == win10::idd::FALSE { bail!("{}", win10::get_last_msg()?); } else { *H_SW_DEVICE.lock().unwrap() = h_sw_device as u64; - Ok(()) } } + Ok(()) } -#[cfg(windows)] pub fn close_device() { + #[cfg(windows)] unsafe { win10::idd::DeviceClose(*H_SW_DEVICE.lock().unwrap() as win10::idd::HSWDEVICE); *H_SW_DEVICE.lock().unwrap() = 0; } } -#[cfg(windows)] pub fn plug_in_monitor() -> ResultType<()> { + #[cfg(windows)] unsafe { - if win10::idd::MonitorPlugIn(0, 0, 30) == win10::idd::FALSE { + let monitor_index = 0 as u32; + let plug_in_monitors = &mut *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()?); } - Ok(()) + (*plug_in_monitors).push(monitor_index); } + Ok(()) } -#[cfg(windows)] pub fn plug_out_monitor() -> ResultType<()> { + #[cfg(windows)] unsafe { - if win10::idd::MonitorPlugOut(0) == win10::idd::FALSE { + let monitor_index = 0 as u32; + if win10::idd::MonitorPlugOut(monitor_index) == win10::idd::FALSE { bail!("{}", win10::get_last_msg()?); } - Ok(()) + let plug_in_monitors = &mut *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(()) +} + +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(), + ) + { + bail!("{}", win10::get_last_msg()?); + } + } + Ok(()) } diff --git a/src/server/video_service.rs b/src/server/video_service.rs index 95e7f5aae..429cff6ce 100644 --- a/src/server/video_service.rs +++ b/src/server/video_service.rs @@ -32,7 +32,6 @@ use std::{ io::ErrorKind::WouldBlock, time::{self, Duration, Instant}, }; -#[cfg(windows)] use virtual_display; const WAIT_BASE: i32 = 17; @@ -123,64 +122,9 @@ impl VideoFrameController { } } -#[derive(Clone)] -pub struct VideoService(GenericService); - -impl Service for VideoService { - fn name(&self) -> &'static str { - self.0.name() - } - fn on_subscribe(&self, sub: ConnInner) { - self.0.on_subscribe(sub) - } - fn on_unsubscribe(&self, id: i32) { - self.0.on_unsubscribe(id) - } - fn is_subed(&self, id: i32) -> bool { - self.0.is_subed(id) - } - fn join(&self) { - self.0.join() - } -} - -impl Drop for VideoService { - fn drop(&mut self) { - #[cfg(windows)] - virtual_display::close_device() - } -} - -impl VideoService { - fn new() -> Self { - #[cfg(windows)] - if let Err(e) = virtual_display::create_device() { - log::error!("Create device failed {}", e); - } - #[cfg(windows)] - match Display::all() { - Ok(displays) => { - if displays.len() == 0 { - log::info!("Detect no displays, try create monitor"); - if virtual_display::is_device_created() { - if let Err(e) = virtual_display::plug_in_monitor() { - log::error!("Plug in monitor failed {}", e); - } - } - } - } - Err(e) => { - log::error!("Get all displays failed {}", e) - } - } - - VideoService(GenericService::new(NAME, true)) - } -} - -pub fn new() -> VideoService { - let sp = VideoService::new(); - sp.0.run(run); +pub fn new() -> GenericService { + let sp = GenericService::new(NAME, true); + sp.run(run); sp } @@ -190,7 +134,7 @@ fn check_display_changed( last_width: usize, last_hegiht: usize, ) -> bool { - let displays = match Display::all() { + let displays = match try_get_displays() { Ok(d) => d, _ => return false, }; @@ -355,6 +299,11 @@ fn run(sp: GenericService) -> ResultType<()> { std::thread::sleep(spf - elapsed); } } + + // Close device, if there are no connections + if virtual_display::is_device_created() { + virtual_display::close_device() + } Ok(()) } @@ -436,7 +385,7 @@ fn handle_one_frame( } fn get_display_num() -> usize { - if let Ok(d) = Display::all() { + if let Ok(d) = try_get_displays() { d.len() } else { 0 @@ -450,7 +399,7 @@ pub fn get_displays() -> ResultType<(usize, Vec)> { } let mut displays = Vec::new(); let mut primary = 0; - for (i, d) in Display::all()?.iter().enumerate() { + for (i, d) in try_get_displays()?.iter().enumerate() { if d.is_primary() { primary = i; } @@ -485,7 +434,7 @@ pub fn refresh() { } fn get_primary() -> usize { - if let Ok(all) = Display::all() { + if let Ok(all) = try_get_displays() { for (i, d) in all.iter().enumerate() { if d.is_primary() { return i; @@ -499,17 +448,38 @@ pub fn switch_to_primary() { switch_display(get_primary() as _); } -fn get_current_display() -> ResultType<(usize, usize, Display)> { - let mut current = *CURRENT_DISPLAY.lock().unwrap() as usize; +fn try_get_displays() -> ResultType> { let mut displays = Display::all()?; if displays.len() == 0 { - // try plugin monitor - #[cfg(windows)] + // Try plugin monitor + if !virtual_display::is_device_created() { + if let Err(e) = virtual_display::create_device() { + log::error!("Create device failed {}", e); + } + } if virtual_display::is_device_created() { if let Err(e) = virtual_display::plug_in_monitor() { log::error!("Plug in monitor failed {}", e); + } else { + if let Err(e) = virtual_display::update_monitor_modes() { + log::error!("Update monitor modes failed {}", e); + } } } + displays = Display::all()?; + } else if displays.len() > 1 { + // If more than one displays exists, close RustDeskVirtualDisplay + if virtual_display::is_device_created() { + virtual_display::close_device() + } + } + Ok(displays) +} + +fn get_current_display() -> ResultType<(usize, usize, Display)> { + let mut current = *CURRENT_DISPLAY.lock().unwrap() as usize; + let mut displays = try_get_displays()?; + if displays.len() == 0 { bail!("No displays"); }