add virtual display

Signed-off-by: fufesou <shuanglongchen@yeah.net>
This commit is contained in:
fufesou 2022-03-12 19:51:55 +08:00
parent e6bf858ae1
commit b734e8aee9
13 changed files with 153 additions and 13 deletions

1
Cargo.lock generated
View File

@ -4186,6 +4186,7 @@ name = "virtual_display"
version = "0.1.0"
dependencies = [
"cc",
"hbb_common",
"lazy_static",
"serde 1.0.136",
"serde_derive",

View File

@ -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;

View File

@ -13,3 +13,4 @@ thiserror = "1.0.30"
lazy_static = "1.4"
serde = "1.0"
serde_derive = "1.0"
hbb_common = { path = "../hbb_common" }

View File

@ -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);
}
}

View File

@ -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<u64> = 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(())
}
}

View File

@ -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))
{

View File

@ -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.

View File

@ -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;

View File

@ -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;

View File

@ -1 +1,4 @@
pub mod idd;
pub mod idd;
pub const DRIVER_INSTALL_PATH: &str = "RustDeskIddDriver/RustDeskIddDriver.inf";
pub const DRIVER_DOWNLOAD_URL: &str = "";

View File

@ -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();

View File

@ -19,6 +19,7 @@ use std::{
process::Child,
sync::{Arc, Mutex},
};
use virtual_display;
pub type Childs = Arc<Mutex<(bool, HashMap<(String, String), Child>)>>;
@ -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();

View File

@ -168,6 +168,7 @@ class MyIdMenu: Reactor.Component {
<li #custom-server>{translate('ID/Relay Server')}</li>
<li #whitelist title={translate('whitelist_tip')}>{translate('IP Whitelisting')}</li>
<li #socks5-server>{translate('Socks5 Proxy')}</li>
{is_win ? <li #install-virtual-display>Install virtual display</li> : ""}
<div .separator />
<li #stop-service class={service_stopped ? "line-through" : "selected"}><span>{svg_checkmark}</span>{translate("Enable Service")}</li>
<DirectServer />
@ -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") {