virtual display: plugout monitor on disconnecting, debug failed, may crash...
Signed-off-by: fufesou <shuanglongchen@yeah.net>
This commit is contained in:
parent
974c259a3d
commit
117bbb3409
@ -13,4 +13,4 @@ thiserror = "1.0.30"
|
|||||||
lazy_static = "1.4"
|
lazy_static = "1.4"
|
||||||
serde = "1.0"
|
serde = "1.0"
|
||||||
serde_derive = "1.0"
|
serde_derive = "1.0"
|
||||||
hbb_common = { path = "../hbb_common" }
|
hbb_common = { path = "../hbb_common" }
|
||||||
|
@ -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).
|
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).
|
**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
|
#### tested platforms
|
||||||
|
|
||||||
- [x] 19041
|
- [x] 19041
|
||||||
|
- [x] 19043
|
||||||
|
|
||||||
### win7
|
### win7
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ use std::{ffi::CString, path::Path, sync::Mutex};
|
|||||||
|
|
||||||
lazy_static::lazy_static! {
|
lazy_static::lazy_static! {
|
||||||
static ref H_SW_DEVICE: Mutex<u64> = Mutex::new(0);
|
static ref H_SW_DEVICE: Mutex<u64> = Mutex::new(0);
|
||||||
|
static ref MONITOR_PLUGIN: Mutex<Vec<u32>> = Mutex::new(Vec::new());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn download_driver() -> ResultType<()> {
|
pub fn download_driver() -> ResultType<()> {
|
||||||
@ -90,46 +91,88 @@ pub fn is_device_created() -> bool {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
|
||||||
pub fn create_device() -> ResultType<()> {
|
pub fn create_device() -> ResultType<()> {
|
||||||
if is_device_created() {
|
if is_device_created() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
#[cfg(windows)]
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut h_sw_device = *H_SW_DEVICE.lock().unwrap() as win10::idd::HSWDEVICE;
|
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 {
|
if win10::idd::DeviceCreate(&mut h_sw_device) == win10::idd::FALSE {
|
||||||
bail!("{}", win10::get_last_msg()?);
|
bail!("{}", win10::get_last_msg()?);
|
||||||
} else {
|
} else {
|
||||||
*H_SW_DEVICE.lock().unwrap() = h_sw_device as u64;
|
*H_SW_DEVICE.lock().unwrap() = h_sw_device as u64;
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
|
||||||
pub fn close_device() {
|
pub fn close_device() {
|
||||||
|
#[cfg(windows)]
|
||||||
unsafe {
|
unsafe {
|
||||||
win10::idd::DeviceClose(*H_SW_DEVICE.lock().unwrap() as win10::idd::HSWDEVICE);
|
win10::idd::DeviceClose(*H_SW_DEVICE.lock().unwrap() as win10::idd::HSWDEVICE);
|
||||||
*H_SW_DEVICE.lock().unwrap() = 0;
|
*H_SW_DEVICE.lock().unwrap() = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
|
||||||
pub fn plug_in_monitor() -> ResultType<()> {
|
pub fn plug_in_monitor() -> ResultType<()> {
|
||||||
|
#[cfg(windows)]
|
||||||
unsafe {
|
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()?);
|
bail!("{}", win10::get_last_msg()?);
|
||||||
}
|
}
|
||||||
Ok(())
|
(*plug_in_monitors).push(monitor_index);
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
|
||||||
pub fn plug_out_monitor() -> ResultType<()> {
|
pub fn plug_out_monitor() -> ResultType<()> {
|
||||||
|
#[cfg(windows)]
|
||||||
unsafe {
|
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()?);
|
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(())
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,6 @@ use std::{
|
|||||||
io::ErrorKind::WouldBlock,
|
io::ErrorKind::WouldBlock,
|
||||||
time::{self, Duration, Instant},
|
time::{self, Duration, Instant},
|
||||||
};
|
};
|
||||||
#[cfg(windows)]
|
|
||||||
use virtual_display;
|
use virtual_display;
|
||||||
|
|
||||||
const WAIT_BASE: i32 = 17;
|
const WAIT_BASE: i32 = 17;
|
||||||
@ -123,64 +122,9 @@ impl VideoFrameController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
pub fn new() -> GenericService {
|
||||||
pub struct VideoService(GenericService);
|
let sp = GenericService::new(NAME, true);
|
||||||
|
sp.run(run);
|
||||||
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);
|
|
||||||
sp
|
sp
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -190,7 +134,7 @@ fn check_display_changed(
|
|||||||
last_width: usize,
|
last_width: usize,
|
||||||
last_hegiht: usize,
|
last_hegiht: usize,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let displays = match Display::all() {
|
let displays = match try_get_displays() {
|
||||||
Ok(d) => d,
|
Ok(d) => d,
|
||||||
_ => return false,
|
_ => return false,
|
||||||
};
|
};
|
||||||
@ -355,6 +299,11 @@ fn run(sp: GenericService) -> ResultType<()> {
|
|||||||
std::thread::sleep(spf - elapsed);
|
std::thread::sleep(spf - elapsed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Close device, if there are no connections
|
||||||
|
if virtual_display::is_device_created() {
|
||||||
|
virtual_display::close_device()
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -436,7 +385,7 @@ fn handle_one_frame(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get_display_num() -> usize {
|
fn get_display_num() -> usize {
|
||||||
if let Ok(d) = Display::all() {
|
if let Ok(d) = try_get_displays() {
|
||||||
d.len()
|
d.len()
|
||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
@ -450,7 +399,7 @@ pub fn get_displays() -> ResultType<(usize, Vec<DisplayInfo>)> {
|
|||||||
}
|
}
|
||||||
let mut displays = Vec::new();
|
let mut displays = Vec::new();
|
||||||
let mut primary = 0;
|
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() {
|
if d.is_primary() {
|
||||||
primary = i;
|
primary = i;
|
||||||
}
|
}
|
||||||
@ -485,7 +434,7 @@ pub fn refresh() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get_primary() -> usize {
|
fn get_primary() -> usize {
|
||||||
if let Ok(all) = Display::all() {
|
if let Ok(all) = try_get_displays() {
|
||||||
for (i, d) in all.iter().enumerate() {
|
for (i, d) in all.iter().enumerate() {
|
||||||
if d.is_primary() {
|
if d.is_primary() {
|
||||||
return i;
|
return i;
|
||||||
@ -499,17 +448,38 @@ pub fn switch_to_primary() {
|
|||||||
switch_display(get_primary() as _);
|
switch_display(get_primary() as _);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_current_display() -> ResultType<(usize, usize, Display)> {
|
fn try_get_displays() -> ResultType<Vec<Display>> {
|
||||||
let mut current = *CURRENT_DISPLAY.lock().unwrap() as usize;
|
|
||||||
let mut displays = Display::all()?;
|
let mut displays = Display::all()?;
|
||||||
if displays.len() == 0 {
|
if displays.len() == 0 {
|
||||||
// try plugin monitor
|
// Try plugin monitor
|
||||||
#[cfg(windows)]
|
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 virtual_display::is_device_created() {
|
||||||
if let Err(e) = virtual_display::plug_in_monitor() {
|
if let Err(e) = virtual_display::plug_in_monitor() {
|
||||||
log::error!("Plug in monitor failed {}", e);
|
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");
|
bail!("No displays");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user