mirror of
https://github.com/rustdesk/rustdesk.git
synced 2024-12-18 13:37:52 +08:00
fix clipboard crash and https://github.com/rustdesk/rustdesk/issues/302
This commit is contained in:
parent
252d3cb797
commit
a30aaebc72
@ -9,8 +9,8 @@ extern "C" {
|
|||||||
src_stride_argb: c_int,
|
src_stride_argb: c_int,
|
||||||
dst_argb: *mut u8,
|
dst_argb: *mut u8,
|
||||||
dst_stride_argb: c_int,
|
dst_stride_argb: c_int,
|
||||||
width: c_int,
|
src_width: c_int,
|
||||||
height: c_int,
|
src_height: c_int,
|
||||||
mode: c_int,
|
mode: c_int,
|
||||||
) -> c_int;
|
) -> c_int;
|
||||||
|
|
||||||
|
@ -3,32 +3,20 @@ pub mod gdi;
|
|||||||
pub use gdi::CapturerGDI;
|
pub use gdi::CapturerGDI;
|
||||||
|
|
||||||
use winapi::{
|
use winapi::{
|
||||||
shared::dxgi::{
|
shared::{
|
||||||
CreateDXGIFactory1, IDXGIAdapter1, IDXGIFactory1, IDXGIResource, IDXGISurface,
|
dxgi::*,
|
||||||
IID_IDXGIFactory1, IID_IDXGISurface, DXGI_MAP_READ, DXGI_OUTPUT_DESC,
|
dxgi1_2::*,
|
||||||
DXGI_RESOURCE_PRIORITY_MAXIMUM,
|
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,
|
um::{
|
||||||
// shared::dxgiformat::{DXGI_FORMAT, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_420_OPAQUE},
|
d3d11::*, d3dcommon::D3D_DRIVER_TYPE_UNKNOWN, unknwnbase::IUnknown, wingdi::*,
|
||||||
shared::dxgi1_2::{IDXGIOutput1, IID_IDXGIOutput1},
|
winnt::HRESULT, winuser::*,
|
||||||
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::{
|
|
||||||
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<T>(*mut T);
|
pub struct ComPtr<T>(*mut T);
|
||||||
@ -54,12 +42,11 @@ pub struct Capturer {
|
|||||||
duplication: ComPtr<IDXGIOutputDuplication>,
|
duplication: ComPtr<IDXGIOutputDuplication>,
|
||||||
fastlane: bool,
|
fastlane: bool,
|
||||||
surface: ComPtr<IDXGISurface>,
|
surface: ComPtr<IDXGISurface>,
|
||||||
data: *const u8,
|
|
||||||
len: usize,
|
|
||||||
width: usize,
|
width: usize,
|
||||||
height: usize,
|
height: usize,
|
||||||
use_yuv: bool,
|
use_yuv: bool,
|
||||||
yuv: Vec<u8>,
|
yuv: Vec<u8>,
|
||||||
|
rotated: Vec<u8>,
|
||||||
gdi_capturer: Option<CapturerGDI>,
|
gdi_capturer: Option<CapturerGDI>,
|
||||||
gdi_buffer: Vec<u8>,
|
gdi_buffer: Vec<u8>,
|
||||||
}
|
}
|
||||||
@ -158,10 +145,9 @@ impl Capturer {
|
|||||||
width: display.width() as usize,
|
width: display.width() as usize,
|
||||||
height: display.height() as usize,
|
height: display.height() as usize,
|
||||||
display,
|
display,
|
||||||
data: ptr::null(),
|
|
||||||
len: 0,
|
|
||||||
use_yuv,
|
use_yuv,
|
||||||
yuv: Vec::new(),
|
yuv: Vec::new(),
|
||||||
|
rotated: Vec::new(),
|
||||||
gdi_capturer,
|
gdi_capturer,
|
||||||
gdi_buffer: Vec::new(),
|
gdi_buffer: Vec::new(),
|
||||||
})
|
})
|
||||||
@ -181,10 +167,9 @@ impl Capturer {
|
|||||||
self.gdi_capturer.take();
|
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 frame = ptr::null_mut();
|
||||||
let mut info = mem::MaybeUninit::uninit().assume_init();
|
let mut info = mem::MaybeUninit::uninit().assume_init();
|
||||||
self.data = ptr::null();
|
|
||||||
|
|
||||||
wrap_hresult((*self.duplication.0).AcquireNextFrame(timeout, &mut info, &mut frame))?;
|
wrap_hresult((*self.duplication.0).AcquireNextFrame(timeout, &mut info, &mut frame))?;
|
||||||
let frame = ComPtr(frame);
|
let frame = ComPtr(frame);
|
||||||
@ -200,9 +185,7 @@ impl Capturer {
|
|||||||
self.surface = ComPtr(self.ohgodwhat(frame.0)?);
|
self.surface = ComPtr(self.ohgodwhat(frame.0)?);
|
||||||
wrap_hresult((*self.surface.0).Map(&mut rect, DXGI_MAP_READ))?;
|
wrap_hresult((*self.surface.0).Map(&mut rect, DXGI_MAP_READ))?;
|
||||||
}
|
}
|
||||||
self.data = rect.pBits;
|
Ok((rect.pBits, rect.Pitch))
|
||||||
self.len = self.height * rect.Pitch as usize;
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy from GPU memory to system memory
|
// copy from GPU memory to system memory
|
||||||
@ -257,8 +240,42 @@ impl Capturer {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.unmap();
|
self.unmap();
|
||||||
self.load_frame(timeout)?;
|
let r = self.load_frame(timeout)?;
|
||||||
slice::from_raw_parts(self.data, self.len)
|
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({
|
Ok({
|
||||||
@ -478,7 +495,10 @@ pub struct Display {
|
|||||||
gdi: bool,
|
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 {
|
impl Display {
|
||||||
pub fn width(&self) -> LONG {
|
pub fn width(&self) -> LONG {
|
||||||
|
@ -95,7 +95,10 @@ pub fn update_clipboard(clipboard: Clipboard, old: Option<&Arc<Mutex<String>>>)
|
|||||||
let side = if old.is_none() { "host" } else { "client" };
|
let side = if old.is_none() { "host" } else { "client" };
|
||||||
let old = if let Some(old) = old { old } else { &CONTENT };
|
let old = if let Some(old) = old { old } else { &CONTENT };
|
||||||
*old.lock().unwrap() = content.clone();
|
*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);
|
log::debug!("{} updated on {}", CLIPBOARD_NAME, side);
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
@ -240,7 +243,8 @@ async fn test_nat_type_() -> ResultType<bool> {
|
|||||||
let rendezvous_server = get_rendezvous_server(100).await;
|
let rendezvous_server = get_rendezvous_server(100).await;
|
||||||
let server1 = rendezvous_server;
|
let server1 = rendezvous_server;
|
||||||
let mut server2 = server1;
|
let mut server2 = server1;
|
||||||
if server1.port() == 0 { // offline
|
if server1.port() == 0 {
|
||||||
|
// offline
|
||||||
// avoid overflow crash
|
// avoid overflow crash
|
||||||
bail!("Offline");
|
bail!("Offline");
|
||||||
}
|
}
|
||||||
|
@ -97,8 +97,12 @@ mod listen {
|
|||||||
|
|
||||||
fn trigger(ctx: &mut ClipboardContext) {
|
fn trigger(ctx: &mut ClipboardContext) {
|
||||||
let _ = match ctx.get_text() {
|
let _ = match ctx.get_text() {
|
||||||
Ok(text) => ctx.set_text(text),
|
Ok(text) => {
|
||||||
Err(_) => ctx.set_text(Default::default()),
|
if !text.is_empty() {
|
||||||
|
ctx.set_text(text).ok();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(_) => {}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -220,7 +220,7 @@ fn run(sp: GenericService) -> ResultType<()> {
|
|||||||
let start = time::Instant::now();
|
let start = time::Instant::now();
|
||||||
let mut last_check_displays = time::Instant::now();
|
let mut last_check_displays = time::Instant::now();
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
let mut try_gdi = true;
|
let mut try_gdi = 1;
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
log::info!("gdi: {}", c.is_gdi());
|
log::info!("gdi: {}", c.is_gdi());
|
||||||
while sp.ok() {
|
while sp.ok() {
|
||||||
@ -261,7 +261,7 @@ fn run(sp: GenericService) -> ResultType<()> {
|
|||||||
frame_controller.set_send(now, send_conn_ids);
|
frame_controller.set_send(now, send_conn_ids);
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
{
|
{
|
||||||
try_gdi = false;
|
try_gdi = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(ref e) if e.kind() == WouldBlock => {
|
Err(ref e) if e.kind() == WouldBlock => {
|
||||||
@ -271,10 +271,13 @@ fn run(sp: GenericService) -> ResultType<()> {
|
|||||||
wait = 0
|
wait = 0
|
||||||
}
|
}
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
if try_gdi && !c.is_gdi() {
|
if try_gdi > 0 && !c.is_gdi() {
|
||||||
c.set_gdi();
|
if try_gdi > 3 {
|
||||||
try_gdi = false;
|
c.set_gdi();
|
||||||
log::info!("No image, fall back to gdi");
|
try_gdi = 0;
|
||||||
|
log::info!("No image, fall back to gdi");
|
||||||
|
}
|
||||||
|
try_gdi += 1;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user