From a30aaebc72fc6e8eeb1d711477dfb9133698f8de Mon Sep 17 00:00:00 2001 From: open-trade Date: Thu, 23 Dec 2021 17:44:44 +0800 Subject: [PATCH] fix clipboard crash and https://github.com/rustdesk/rustdesk/issues/302 --- libs/scrap/src/common/convert.rs | 4 +- libs/scrap/src/dxgi/mod.rs | 92 +++++++++++++++++++------------- src/common.rs | 8 ++- src/server/clipboard_service.rs | 8 ++- src/server/video_service.rs | 15 +++--- 5 files changed, 79 insertions(+), 48 deletions(-) diff --git a/libs/scrap/src/common/convert.rs b/libs/scrap/src/common/convert.rs index 2cf9a4eca..fdc90a806 100644 --- a/libs/scrap/src/common/convert.rs +++ b/libs/scrap/src/common/convert.rs @@ -9,8 +9,8 @@ extern "C" { src_stride_argb: c_int, dst_argb: *mut u8, dst_stride_argb: c_int, - width: c_int, - height: c_int, + src_width: c_int, + src_height: c_int, mode: c_int, ) -> c_int; diff --git a/libs/scrap/src/dxgi/mod.rs b/libs/scrap/src/dxgi/mod.rs index f6bc704a9..677811b93 100644 --- a/libs/scrap/src/dxgi/mod.rs +++ b/libs/scrap/src/dxgi/mod.rs @@ -3,32 +3,20 @@ pub mod gdi; pub use gdi::CapturerGDI; use winapi::{ - shared::dxgi::{ - CreateDXGIFactory1, IDXGIAdapter1, IDXGIFactory1, IDXGIResource, IDXGISurface, - IID_IDXGIFactory1, IID_IDXGISurface, DXGI_MAP_READ, DXGI_OUTPUT_DESC, - DXGI_RESOURCE_PRIORITY_MAXIMUM, + shared::{ + dxgi::*, + dxgi1_2::*, + dxgitype::*, + minwindef::{DWORD, FALSE, TRUE, UINT}, + ntdef::LONG, + windef::HMONITOR, + winerror::*, + // dxgiformat::{DXGI_FORMAT, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_420_OPAQUE}, }, - shared::dxgi1_2::IDXGIOutputDuplication, - // shared::dxgiformat::{DXGI_FORMAT, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_420_OPAQUE}, - shared::dxgi1_2::{IDXGIOutput1, IID_IDXGIOutput1}, - shared::dxgitype::DXGI_MODE_ROTATION, - shared::minwindef::{DWORD, FALSE, TRUE, UINT}, - shared::ntdef::LONG, - shared::windef::HMONITOR, - shared::winerror::{ - DXGI_ERROR_ACCESS_LOST, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_NOT_CURRENTLY_AVAILABLE, - DXGI_ERROR_SESSION_DISCONNECTED, DXGI_ERROR_UNSUPPORTED, DXGI_ERROR_WAIT_TIMEOUT, - E_ACCESSDENIED, E_INVALIDARG, S_OK, + um::{ + d3d11::*, d3dcommon::D3D_DRIVER_TYPE_UNKNOWN, unknwnbase::IUnknown, wingdi::*, + winnt::HRESULT, winuser::*, }, - um::d3d11::{ - D3D11CreateDevice, ID3D11Device, ID3D11DeviceContext, ID3D11Texture2D, IID_ID3D11Texture2D, - D3D11_CPU_ACCESS_READ, D3D11_SDK_VERSION, D3D11_USAGE_STAGING, - }, - um::d3dcommon::D3D_DRIVER_TYPE_UNKNOWN, - um::unknwnbase::IUnknown, - um::wingdi::*, - um::winnt::HRESULT, - um::winuser::*, }; pub struct ComPtr(*mut T); @@ -54,12 +42,11 @@ pub struct Capturer { duplication: ComPtr, fastlane: bool, surface: ComPtr, - data: *const u8, - len: usize, width: usize, height: usize, use_yuv: bool, yuv: Vec, + rotated: Vec, gdi_capturer: Option, gdi_buffer: Vec, } @@ -158,10 +145,9 @@ impl Capturer { width: display.width() as usize, height: display.height() as usize, display, - data: ptr::null(), - len: 0, use_yuv, yuv: Vec::new(), + rotated: Vec::new(), gdi_capturer, gdi_buffer: Vec::new(), }) @@ -181,10 +167,9 @@ impl Capturer { self.gdi_capturer.take(); } - unsafe fn load_frame(&mut self, timeout: UINT) -> io::Result<()> { + unsafe fn load_frame(&mut self, timeout: UINT) -> io::Result<(*const u8, i32)> { let mut frame = ptr::null_mut(); let mut info = mem::MaybeUninit::uninit().assume_init(); - self.data = ptr::null(); wrap_hresult((*self.duplication.0).AcquireNextFrame(timeout, &mut info, &mut frame))?; let frame = ComPtr(frame); @@ -200,9 +185,7 @@ impl Capturer { self.surface = ComPtr(self.ohgodwhat(frame.0)?); wrap_hresult((*self.surface.0).Map(&mut rect, DXGI_MAP_READ))?; } - self.data = rect.pBits; - self.len = self.height * rect.Pitch as usize; - Ok(()) + Ok((rect.pBits, rect.Pitch)) } // copy from GPU memory to system memory @@ -257,8 +240,42 @@ impl Capturer { } } else { self.unmap(); - self.load_frame(timeout)?; - slice::from_raw_parts(self.data, self.len) + let r = self.load_frame(timeout)?; + let rotate = match self.display.rotation() { + DXGI_MODE_ROTATION_IDENTITY | DXGI_MODE_ROTATION_UNSPECIFIED => 0, + DXGI_MODE_ROTATION_ROTATE90 => 90, + DXGI_MODE_ROTATION_ROTATE180 => 180, + DXGI_MODE_ROTATION_ROTATE270 => 270, + _ => { + return Err(io::Error::new( + io::ErrorKind::Other, + "Unknown roration".to_string(), + )); + } + }; + if rotate == 0 { + slice::from_raw_parts(r.0, r.1 as usize * self.height) + } else { + self.rotated.resize(self.width * self.height * 4, 0); + crate::common::ARGBRotate( + r.0, + r.1, + self.rotated.as_mut_ptr(), + 4 * self.width as i32, + if rotate == 180 { + self.width + } else { + self.height + } as _, + if rotate != 180 { + self.width + } else { + self.height + } as _, + rotate, + ); + &self.rotated[..] + } } }; Ok({ @@ -478,7 +495,10 @@ pub struct Display { gdi: bool, } -// https://github.com/dchapyshev/aspia/blob/59233c5d01a4d03ed6de19b03ce77d61a6facf79/source/base/desktop/win/screen_capture_utils.cc +// optimized for updated region +// https://github.com/dchapyshev/aspia/blob/master/source/base/desktop/win/dxgi_output_duplicator.cc +// rotation +// https://github.com/bryal/dxgcap-rs/blob/master/src/lib.rs impl Display { pub fn width(&self) -> LONG { diff --git a/src/common.rs b/src/common.rs index e5a7e4f99..921516311 100644 --- a/src/common.rs +++ b/src/common.rs @@ -95,7 +95,10 @@ pub fn update_clipboard(clipboard: Clipboard, old: Option<&Arc>>) let side = if old.is_none() { "host" } else { "client" }; let old = if let Some(old) = old { old } else { &CONTENT }; *old.lock().unwrap() = content.clone(); - allow_err!(ctx.set_text(content)); + if !content.is_empty() { + // empty content make ctx.set_text crash + allow_err!(ctx.set_text(content)); + } log::debug!("{} updated on {}", CLIPBOARD_NAME, side); } Err(err) => { @@ -240,7 +243,8 @@ async fn test_nat_type_() -> ResultType { let rendezvous_server = get_rendezvous_server(100).await; let server1 = rendezvous_server; let mut server2 = server1; - if server1.port() == 0 { // offline + if server1.port() == 0 { + // offline // avoid overflow crash bail!("Offline"); } diff --git a/src/server/clipboard_service.rs b/src/server/clipboard_service.rs index be496c859..0a1745fcb 100644 --- a/src/server/clipboard_service.rs +++ b/src/server/clipboard_service.rs @@ -97,8 +97,12 @@ mod listen { fn trigger(ctx: &mut ClipboardContext) { let _ = match ctx.get_text() { - Ok(text) => ctx.set_text(text), - Err(_) => ctx.set_text(Default::default()), + Ok(text) => { + if !text.is_empty() { + ctx.set_text(text).ok(); + } + } + Err(_) => {} }; } } diff --git a/src/server/video_service.rs b/src/server/video_service.rs index 9ec5f9849..4d8f6dbe4 100644 --- a/src/server/video_service.rs +++ b/src/server/video_service.rs @@ -220,7 +220,7 @@ fn run(sp: GenericService) -> ResultType<()> { let start = time::Instant::now(); let mut last_check_displays = time::Instant::now(); #[cfg(windows)] - let mut try_gdi = true; + let mut try_gdi = 1; #[cfg(windows)] log::info!("gdi: {}", c.is_gdi()); while sp.ok() { @@ -261,7 +261,7 @@ fn run(sp: GenericService) -> ResultType<()> { frame_controller.set_send(now, send_conn_ids); #[cfg(windows)] { - try_gdi = false; + try_gdi = 0; } } Err(ref e) if e.kind() == WouldBlock => { @@ -271,10 +271,13 @@ fn run(sp: GenericService) -> ResultType<()> { wait = 0 } #[cfg(windows)] - if try_gdi && !c.is_gdi() { - c.set_gdi(); - try_gdi = false; - log::info!("No image, fall back to gdi"); + if try_gdi > 0 && !c.is_gdi() { + if try_gdi > 3 { + c.set_gdi(); + try_gdi = 0; + log::info!("No image, fall back to gdi"); + } + try_gdi += 1; } continue; }