diff --git a/Cargo.lock b/Cargo.lock index 0c2daa406..33bc04259 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4186,6 +4186,7 @@ name = "virtual_display" version = "0.1.0" dependencies = [ "cc", + "hbb_common", "lazy_static", "serde 1.0.136", "serde_derive", diff --git a/libs/hbb_common/src/lib.rs b/libs/hbb_common/src/lib.rs index e66eed7d0..81871bf26 100644 --- a/libs/hbb_common/src/lib.rs +++ b/libs/hbb_common/src/lib.rs @@ -27,13 +27,14 @@ pub use anyhow::{self, bail}; pub use futures_util; pub mod config; pub mod fs; +pub use lazy_static; +pub use mac_address; pub use rand; pub use regex; pub use sodiumoxide; pub use tokio_socks; pub use tokio_socks::IntoTargetAddr; pub use tokio_socks::TargetAddr; -pub use mac_address; #[cfg(feature = "quic")] pub type Stream = quic::Connection; diff --git a/libs/virtual_display/Cargo.toml b/libs/virtual_display/Cargo.toml index 19da85222..0f7535d46 100644 --- a/libs/virtual_display/Cargo.toml +++ b/libs/virtual_display/Cargo.toml @@ -13,3 +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 diff --git a/libs/virtual_display/examples/idd_controller.rs b/libs/virtual_display/examples/idd_controller.rs index a91b39181..0bcb79d66 100644 --- a/libs/virtual_display/examples/idd_controller.rs +++ b/libs/virtual_display/examples/idd_controller.rs @@ -1,5 +1,5 @@ #[cfg(windows)] -use virtual_display::win10::idd; +use virtual_display::win10::{idd, DRIVER_INSTALL_PATH}; use std::{ ffi::{CStr, CString}, @@ -24,9 +24,9 @@ fn prompt_input() -> u8 { .unwrap_or(0) } -unsafe fn plug_in(index: idd::UINT) { +unsafe fn plug_in(index: idd::UINT, edid: idd::UINT) { println!("Plug in monitor begin"); - if idd::FALSE == idd::MonitorPlugIn(index, 25) { + if idd::FALSE == idd::MonitorPlugIn(index, edid, 25) { println!("{}", CStr::from_ptr(idd::GetLastMsg()).to_str().unwrap()); } else { println!("Plug in monitor done"); @@ -58,8 +58,7 @@ unsafe fn plug_out(index: idd::UINT) { } fn main() { - let relative_path = "RustDeskIddDriver/RustDeskIddDriver.inf"; - let abs_path = Path::new(relative_path).canonicalize().unwrap(); + let abs_path = Path::new(DRIVER_INSTALL_PATH).canonicalize().unwrap(); let full_inf_path = abs_path.to_str().unwrap(); unsafe { @@ -121,9 +120,9 @@ fn main() { h_sw_device = invalid_device; println!("Close device done"); } - '1' => plug_in(0), - '2' => plug_in(1), - '3' => plug_in(2), + '1' => plug_in(0, 0), + '2' => plug_in(1, 0), + '3' => plug_in(2, 0), '4' => plug_out(0), '5' => plug_out(1), '6' => plug_out(2), @@ -133,5 +132,7 @@ fn main() { if !full_inf_path.is_null() { let _ = CString::from_raw(full_inf_path); } + + idd::DeviceClose(h_sw_device); } } diff --git a/libs/virtual_display/src/lib.rs b/libs/virtual_display/src/lib.rs index 425e873d5..2a37fb586 100644 --- a/libs/virtual_display/src/lib.rs +++ b/libs/virtual_display/src/lib.rs @@ -1,2 +1,103 @@ #[cfg(windows)] pub mod win10; + +use hbb_common::{bail, lazy_static, ResultType}; +use std::{ + ffi::{CStr, CString}, + path::Path, + sync::Mutex, +}; + +lazy_static::lazy_static! { + #[cfg(windows)] + static ref H_SW_DEVICE: Mutex = Mutex::new(0); +} + +pub fn download_driver() -> ResultType<()> { + #[cfg(windows)] + let _download_url = win10::DRIVER_DOWNLOAD_URL; + #[cfg(target_os = "linux")] + let _download_url = ""; + + // process download and report progress + + Ok(()) +} + +pub fn install_update_driver() -> ResultType<()> { + #[cfg(windows)] + let install_path = win10::DRIVER_INSTALL_PATH; + #[cfg(not(windows))] + let install_path = ""; + + let abs_path = Path::new(install_path).canonicalize()?; + if !abs_path.exists() { + bail!("{} not exists", install_path) + } + + let full_install_path = match abs_path.to_str() { + Some(p) => CString::new(p)?.into_raw(), + None => bail!("{} not exists", install_path), + }; + + unsafe { + #[cfg(windows)] + { + let mut reboot_required = win10::idd::FALSE; + if win10::idd::InstallUpdate(full_install_path, &mut reboot_required) + == win10::idd::FALSE + { + bail!("{}", CStr::from_ptr(win10::idd::GetLastMsg()).to_str()?); + } + } + } + + Ok(()) +} + +pub fn is_device_created() -> bool { + #[cfg(windows)] + return *H_SW_DEVICE.lock().unwrap() != 0; + #[cfg(not(windows))] + return false; +} + +#[cfg(windows)] +pub fn create_device() -> ResultType<()> { + 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!("{}", CStr::from_ptr(win10::idd::GetLastMsg()).to_str()?); + } else { + *H_SW_DEVICE.lock().unwrap() = h_sw_device as u64; + Ok(()) + } + } +} + +#[cfg(windows)] +pub fn close_device() { + unsafe { + win10::idd::DeviceClose(*H_SW_DEVICE.lock().unwrap() as win10::idd::HSWDEVICE); + } +} + +#[cfg(windows)] +pub fn plug_in_monitor() -> ResultType<()> { + unsafe { + if win10::idd::MonitorPlugIn(0, 0, 30) == win10::idd::FALSE { + bail!("{}", CStr::from_ptr(win10::idd::GetLastMsg()).to_str()?); + } + Ok(()) + } +} + +#[cfg(windows)] +pub fn plug_out_monitor() -> ResultType<()> { + unsafe { + if win10::idd::MonitorPlugOut(0) == win10::idd::FALSE { + bail!("{}", CStr::from_ptr(win10::idd::GetLastMsg()).to_str()?); + } + Ok(()) + } +} diff --git a/libs/virtual_display/src/win10/IddController.c b/libs/virtual_display/src/win10/IddController.c index 49f9beee0..dd18a622d 100644 --- a/libs/virtual_display/src/win10/IddController.c +++ b/libs/virtual_display/src/win10/IddController.c @@ -282,7 +282,7 @@ VOID DeviceClose(HSWDEVICE hSwDevice) } } -BOOL MonitorPlugIn(UINT index, INT retries) +BOOL MonitorPlugIn(UINT index, UINT edid, INT retries) { SetLastMsg("Sucess"); @@ -315,6 +315,7 @@ BOOL MonitorPlugIn(UINT index, INT retries) DWORD junk = 0; CtlPlugIn plugIn; plugIn.ConnectorIndex = index; + plugIn.MonitorEDID = edid; HRESULT hr = CoCreateGuid(&plugIn.ContainerId); if (!SUCCEEDED(hr)) { diff --git a/libs/virtual_display/src/win10/IddController.h b/libs/virtual_display/src/win10/IddController.h index 90d6c4295..f92f72647 100644 --- a/libs/virtual_display/src/win10/IddController.h +++ b/libs/virtual_display/src/win10/IddController.h @@ -70,6 +70,9 @@ VOID DeviceClose(HSWDEVICE hSwDevice); * @brief Plug in monitor. * * @param index [in] Monitor index, should be 0, 1, 2. + * @param edid [in] Monitor edid. + * 0 Modified EDID from Dell S2719DGF + * 1 Modified EDID from Lenovo Y27fA * @param retries [in] Retry times. Retry 1 time / sec. 25~30 seconds may be good choices. * -1 is invalid. * 0 means doing once and no retries. @@ -83,7 +86,7 @@ VOID DeviceClose(HSWDEVICE hSwDevice); * System need some time to prepare the device. * */ -BOOL MonitorPlugIn(UINT index, INT retries); +BOOL MonitorPlugIn(UINT index, UINT edid, INT retries); /** * @brief Plug out monitor. diff --git a/libs/virtual_display/src/win10/Public.h b/libs/virtual_display/src/win10/Public.h index 547cf4351..d7f294a52 100644 --- a/libs/virtual_display/src/win10/Public.h +++ b/libs/virtual_display/src/win10/Public.h @@ -26,8 +26,12 @@ #define STATUS_ERROR_MONITOR_INVALID_PARAM (3 << 30) + 53 #define STATUS_ERROR_MONITOR_OOM (3 << 30) + 54 +#define MONITOR_EDID_MOD_DELL_S2719DGF 0 +#define MONITOR_EDID_MOD_LENOVO_Y27fA 1 + typedef struct _CtlPlugIn { UINT ConnectorIndex; + UINT MonitorEDID; GUID ContainerId; } CtlPlugIn, *PCtlPlugIn; diff --git a/libs/virtual_display/src/win10/idd.rs b/libs/virtual_display/src/win10/idd.rs index 66a90b059..ff614c058 100644 --- a/libs/virtual_display/src/win10/idd.rs +++ b/libs/virtual_display/src/win10/idd.rs @@ -206,7 +206,7 @@ extern "C" { extern "C" { pub fn Uninstall(fullInfPath: LPCTSTR, rebootRequired: PBOOL) -> BOOL; - pub fn MonitorPlugIn(index: UINT, retries: INT) -> BOOL; + pub fn MonitorPlugIn(index: UINT, edid: UINT, retries: INT) -> BOOL; pub fn MonitorPlugOut(index: UINT) -> BOOL; pub fn MonitorModesUpdate(index: UINT, modeCount: UINT, modes: PMonitorMode) -> BOOL; diff --git a/libs/virtual_display/src/win10/mod.rs b/libs/virtual_display/src/win10/mod.rs index d8797d709..549c9a807 100644 --- a/libs/virtual_display/src/win10/mod.rs +++ b/libs/virtual_display/src/win10/mod.rs @@ -1 +1,4 @@ -pub mod idd; \ No newline at end of file +pub mod idd; + +pub const DRIVER_INSTALL_PATH: &str = "RustDeskIddDriver/RustDeskIddDriver.inf"; +pub const DRIVER_DOWNLOAD_URL: &str = ""; diff --git a/src/server/video_service.rs b/src/server/video_service.rs index 68faf178e..5b272273a 100644 --- a/src/server/video_service.rs +++ b/src/server/video_service.rs @@ -32,6 +32,7 @@ use std::{ io::ErrorKind::WouldBlock, time::{self, Duration, Instant}, }; +use virtual_display; const WAIT_BASE: i32 = 17; pub const NAME: &'static str = "video"; @@ -446,6 +447,12 @@ fn get_current_display() -> ResultType<(usize, usize, Display)> { let mut current = *CURRENT_DISPLAY.lock().unwrap() as usize; let mut displays = Display::all()?; if displays.len() == 0 { + // try plugin monitor + if virtual_display::is_device_created() { + if let Err(e) = virtual_display::plug_in_monitor() { + log::error!("plug in monitor failed {}", e) + } + } bail!("No displays"); } let n = displays.len(); diff --git a/src/ui.rs b/src/ui.rs index c59f01299..6c69f14b5 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -19,6 +19,7 @@ use std::{ process::Child, sync::{Arc, Mutex}, }; +use virtual_display; pub type Childs = Arc)>>; @@ -364,6 +365,18 @@ impl UI { } } + // TODO: ui prompt + fn install_virtual_display(&self) { + match virtual_display::install_update_driver() { + Ok(_) => { + log::info!("Virtual Display: install virtual display done"); + } + Err(e) => { + log::error!("Virtual Display: install virtual display failed {}", e); + } + } + } + fn install_path(&mut self) -> String { #[cfg(windows)] return crate::platform::windows::get_install_info().1; @@ -690,6 +703,7 @@ impl sciter::EventHandler for UI { fn get_sound_inputs(); fn set_options(Value); fn set_option(String, String); + fn install_virtual_display(); fn get_software_update_url(); fn get_new_version(); fn get_version(); diff --git a/src/ui/index.tis b/src/ui/index.tis index add5acd94..d43f12760 100644 --- a/src/ui/index.tis +++ b/src/ui/index.tis @@ -168,6 +168,7 @@ class MyIdMenu: Reactor.Component {
  • {translate('ID/Relay Server')}
  • {translate('IP Whitelisting')}
  • {translate('Socks5 Proxy')}
  • + {is_win ?
  • Install virtual display
  • : ""}
  • {svg_checkmark}{translate("Enable Service")}
  • @@ -268,6 +269,8 @@ class MyIdMenu: Reactor.Component { } handler.set_socks(proxy, username, password); }, 240); + } else if (me.id == "install-virtual-display") { + handler.install_virtual_display(); } else if (me.id == "stop-service") { handler.set_option("stop-service", service_stopped ? "" : "Y"); } else if (me.id == "about") {