650 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			650 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
| // logic from webrtc -- https://github.com/shiguredo/libwebrtc/blob/main/modules/desktop_capture/win/screen_capturer_win_magnifier.cc
 | |
| use lazy_static;
 | |
| use std::{
 | |
|     ffi::CString,
 | |
|     io::{Error, ErrorKind, Result},
 | |
|     mem::size_of,
 | |
|     sync::Mutex,
 | |
| };
 | |
| use winapi::{
 | |
|     shared::{
 | |
|         basetsd::SIZE_T,
 | |
|         guiddef::{IsEqualGUID, GUID},
 | |
|         minwindef::{BOOL, DWORD, FALSE, FARPROC, HINSTANCE, HMODULE, HRGN, TRUE, UINT},
 | |
|         ntdef::{LONG, NULL},
 | |
|         windef::{HWND, RECT},
 | |
|         winerror::ERROR_CLASS_ALREADY_EXISTS,
 | |
|     },
 | |
|     um::{
 | |
|         errhandlingapi::GetLastError,
 | |
|         libloaderapi::{FreeLibrary, GetModuleHandleExA, GetProcAddress, LoadLibraryExA},
 | |
|         winuser::*,
 | |
|     },
 | |
| };
 | |
| 
 | |
| pub const MW_FILTERMODE_EXCLUDE: u32 = 0;
 | |
| pub const MW_FILTERMODE_INCLUDE: u32 = 1;
 | |
| pub const GET_MODULE_HANDLE_EX_FLAG_PIN: u32 = 1;
 | |
| pub const GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT: u32 = 2;
 | |
| pub const GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS: u32 = 4;
 | |
| pub const LOAD_LIBRARY_AS_DATAFILE: u32 = 2;
 | |
| pub const LOAD_WITH_ALTERED_SEARCH_PATH: u32 = 8;
 | |
| pub const LOAD_IGNORE_CODE_AUTHZ_LEVEL: u32 = 16;
 | |
| pub const LOAD_LIBRARY_AS_IMAGE_RESOURCE: u32 = 32;
 | |
| pub const LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE: u32 = 64;
 | |
| pub const LOAD_LIBRARY_REQUIRE_SIGNED_TARGET: u32 = 128;
 | |
| pub const LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR: u32 = 256;
 | |
| pub const LOAD_LIBRARY_SEARCH_APPLICATION_DIR: u32 = 512;
 | |
| pub const LOAD_LIBRARY_SEARCH_USER_DIRS: u32 = 1024;
 | |
| pub const LOAD_LIBRARY_SEARCH_SYSTEM32: u32 = 2048;
 | |
| pub const LOAD_LIBRARY_SEARCH_DEFAULT_DIRS: u32 = 4096;
 | |
| pub const LOAD_LIBRARY_SAFE_CURRENT_DIRS: u32 = 8192;
 | |
| pub const LOAD_LIBRARY_SEARCH_SYSTEM32_NO_FORWARDER: u32 = 16384;
 | |
| pub const LOAD_LIBRARY_OS_INTEGRITY_CONTINUITY: u32 = 32768;
 | |
| 
 | |
| extern "C" {
 | |
|     pub static GUID_WICPixelFormat32bppRGBA: GUID;
 | |
| }
 | |
| 
 | |
| lazy_static::lazy_static! {
 | |
|     static ref MAG_BUFFER: Mutex<(bool, Vec<u8>)> =  Default::default();
 | |
| }
 | |
| 
 | |
| pub type REFWICPixelFormatGUID = *const GUID;
 | |
| pub type WICPixelFormatGUID = GUID;
 | |
| 
 | |
| #[allow(non_snake_case)]
 | |
| #[repr(C)]
 | |
| #[derive(Copy, Clone)]
 | |
| pub struct tagMAGIMAGEHEADER {
 | |
|     pub width: UINT,
 | |
|     pub height: UINT,
 | |
|     pub format: WICPixelFormatGUID,
 | |
|     pub stride: UINT,
 | |
|     pub offset: UINT,
 | |
|     pub cbSize: SIZE_T,
 | |
| }
 | |
| pub type MAGIMAGEHEADER = tagMAGIMAGEHEADER;
 | |
| pub type PMAGIMAGEHEADER = *mut tagMAGIMAGEHEADER;
 | |
| 
 | |
| // Function types
 | |
| pub type MagImageScalingCallback = ::std::option::Option<
 | |
|     unsafe extern "C" fn(
 | |
|         hwnd: HWND,
 | |
|         srcdata: *mut ::std::os::raw::c_void,
 | |
|         srcheader: MAGIMAGEHEADER,
 | |
|         destdata: *mut ::std::os::raw::c_void,
 | |
|         destheader: MAGIMAGEHEADER,
 | |
|         unclipped: RECT,
 | |
|         clipped: RECT,
 | |
|         dirty: HRGN,
 | |
|     ) -> BOOL,
 | |
| >;
 | |
| 
 | |
| extern "C" {
 | |
|     pub fn MagShowSystemCursor(fShowCursor: BOOL) -> BOOL;
 | |
| }
 | |
| pub type MagInitializeFunc = ::std::option::Option<unsafe extern "C" fn() -> BOOL>;
 | |
| pub type MagUninitializeFunc = ::std::option::Option<unsafe extern "C" fn() -> BOOL>;
 | |
| pub type MagSetWindowSourceFunc =
 | |
|     ::std::option::Option<unsafe extern "C" fn(hwnd: HWND, rect: RECT) -> BOOL>;
 | |
| pub type MagSetWindowFilterListFunc = ::std::option::Option<
 | |
|     unsafe extern "C" fn(
 | |
|         hwnd: HWND,
 | |
|         dwFilterMode: DWORD,
 | |
|         count: ::std::os::raw::c_int,
 | |
|         pHWND: *mut HWND,
 | |
|     ) -> BOOL,
 | |
| >;
 | |
| pub type MagSetImageScalingCallbackFunc = ::std::option::Option<
 | |
|     unsafe extern "C" fn(hwnd: HWND, callback: MagImageScalingCallback) -> BOOL,
 | |
| >;
 | |
| 
 | |
| #[repr(C)]
 | |
| #[derive(Debug, Clone)]
 | |
| struct MagInterface {
 | |
|     init_succeeded: bool,
 | |
|     lib_handle: HINSTANCE,
 | |
|     pub mag_initialize_func: MagInitializeFunc,
 | |
|     pub mag_uninitialize_func: MagUninitializeFunc,
 | |
|     pub set_window_source_func: MagSetWindowSourceFunc,
 | |
|     pub set_window_filter_list_func: MagSetWindowFilterListFunc,
 | |
|     pub set_image_scaling_callback_func: MagSetImageScalingCallbackFunc,
 | |
| }
 | |
| 
 | |
| // NOTE: MagInitialize and MagUninitialize should not be called in global init and uninit.
 | |
| // If so, strange errors occur.
 | |
| impl MagInterface {
 | |
|     fn new() -> Result<Self> {
 | |
|         let mut s = MagInterface {
 | |
|             init_succeeded: false,
 | |
|             lib_handle: NULL as _,
 | |
|             mag_initialize_func: None,
 | |
|             mag_uninitialize_func: None,
 | |
|             set_window_source_func: None,
 | |
|             set_window_filter_list_func: None,
 | |
|             set_image_scaling_callback_func: None,
 | |
|         };
 | |
|         s.init_succeeded = false;
 | |
|         unsafe {
 | |
|             // load lib
 | |
|             let lib_file_name = "Magnification.dll";
 | |
|             let lib_file_name_c = CString::new(lib_file_name)?;
 | |
|             s.lib_handle = LoadLibraryExA(
 | |
|                 lib_file_name_c.as_ptr() as _,
 | |
|                 NULL,
 | |
|                 LOAD_WITH_ALTERED_SEARCH_PATH,
 | |
|             );
 | |
|             if s.lib_handle.is_null() {
 | |
|                 return Err(Error::new(
 | |
|                     ErrorKind::Other,
 | |
|                     format!(
 | |
|                         "Failed to LoadLibraryExA {}, error {}",
 | |
|                         lib_file_name,
 | |
|                         Error::last_os_error()
 | |
|                     ),
 | |
|                 ));
 | |
|             };
 | |
| 
 | |
|             // load functions
 | |
|             s.mag_initialize_func = Some(std::mem::transmute(Self::load_func(
 | |
|                 s.lib_handle,
 | |
|                 "MagInitialize",
 | |
|             )?));
 | |
|             s.mag_uninitialize_func = Some(std::mem::transmute(Self::load_func(
 | |
|                 s.lib_handle,
 | |
|                 "MagUninitialize",
 | |
|             )?));
 | |
|             s.set_window_source_func = Some(std::mem::transmute(Self::load_func(
 | |
|                 s.lib_handle,
 | |
|                 "MagSetWindowSource",
 | |
|             )?));
 | |
|             s.set_window_filter_list_func = Some(std::mem::transmute(Self::load_func(
 | |
|                 s.lib_handle,
 | |
|                 "MagSetWindowFilterList",
 | |
|             )?));
 | |
|             s.set_image_scaling_callback_func = Some(std::mem::transmute(Self::load_func(
 | |
|                 s.lib_handle,
 | |
|                 "MagSetImageScalingCallback",
 | |
|             )?));
 | |
| 
 | |
|             // MagInitialize
 | |
|             if let Some(init_func) = s.mag_initialize_func {
 | |
|                 if FALSE == init_func() {
 | |
|                     return Err(Error::new(
 | |
|                         ErrorKind::Other,
 | |
|                         format!("Failed to MagInitialize, error {}", Error::last_os_error()),
 | |
|                     ));
 | |
|                 } else {
 | |
|                     s.init_succeeded = true;
 | |
|                 }
 | |
|             } else {
 | |
|                 return Err(Error::new(
 | |
|                     ErrorKind::Other,
 | |
|                     "Unreachable, mag_initialize_func should not be none",
 | |
|                 ));
 | |
|             }
 | |
|         }
 | |
|         Ok(s)
 | |
|     }
 | |
| 
 | |
|     unsafe fn load_func(lib_module: HMODULE, func_name: &str) -> Result<FARPROC> {
 | |
|         let func_name_c = CString::new(func_name)?;
 | |
|         let func = GetProcAddress(lib_module, func_name_c.as_ptr() as _);
 | |
|         if func.is_null() {
 | |
|             return Err(Error::new(
 | |
|                 ErrorKind::Other,
 | |
|                 format!(
 | |
|                     "Failed to GetProcAddress {}, error {}",
 | |
|                     func_name,
 | |
|                     Error::last_os_error()
 | |
|                 ),
 | |
|             ));
 | |
|         }
 | |
|         Ok(func)
 | |
|     }
 | |
| 
 | |
|     pub(super) fn uninit(&mut self) {
 | |
|         if self.init_succeeded {
 | |
|             if let Some(uninit_func) = self.mag_uninitialize_func {
 | |
|                 unsafe {
 | |
|                     if FALSE == uninit_func() {
 | |
|                         println!("Failed MagUninitialize, error {}", Error::last_os_error())
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|             if !self.lib_handle.is_null() {
 | |
|                 unsafe {
 | |
|                     if FALSE == FreeLibrary(self.lib_handle) {
 | |
|                         println!("Failed FreeLibrary, error {}", Error::last_os_error())
 | |
|                     }
 | |
|                 }
 | |
|                 self.lib_handle = NULL as _;
 | |
|             }
 | |
|         }
 | |
|         self.init_succeeded = false;
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl Drop for MagInterface {
 | |
|     fn drop(&mut self) {
 | |
|         self.uninit();
 | |
|     }
 | |
| }
 | |
| 
 | |
| pub struct CapturerMag {
 | |
|     mag_interface: MagInterface,
 | |
|     host_window: HWND,
 | |
|     magnifier_window: HWND,
 | |
| 
 | |
|     magnifier_host_class: CString,
 | |
|     host_window_name: CString,
 | |
|     magnifier_window_class: CString,
 | |
|     magnifier_window_name: CString,
 | |
| 
 | |
|     rect: RECT,
 | |
|     width: usize,
 | |
|     height: usize,
 | |
| }
 | |
| 
 | |
| impl Drop for CapturerMag {
 | |
|     fn drop(&mut self) {
 | |
|         self.destroy_windows();
 | |
|         self.mag_interface.uninit();
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl CapturerMag {
 | |
|     pub(crate) fn is_supported() -> bool {
 | |
|         MagInterface::new().is_ok()
 | |
|     }
 | |
| 
 | |
|     pub(crate) fn new(origin: (i32, i32), width: usize, height: usize) -> Result<Self> {
 | |
|         unsafe {
 | |
|             let x = GetSystemMetrics(SM_XVIRTUALSCREEN);
 | |
|             let y = GetSystemMetrics(SM_YVIRTUALSCREEN);
 | |
|             let w = GetSystemMetrics(SM_CXVIRTUALSCREEN);
 | |
|             let h = GetSystemMetrics(SM_CYVIRTUALSCREEN);
 | |
|             if !(origin.0 >= x as i32
 | |
|                 && origin.1 >= y as i32
 | |
|                 && width <= w as usize
 | |
|                 && height <= h as usize)
 | |
|             {
 | |
|                 return Err(Error::new(
 | |
|                     ErrorKind::Other,
 | |
|                     format!(
 | |
|                         "Failed Check screen rect ({}, {}, {} , {}) to ({}, {}, {}, {})",
 | |
|                         origin.0,
 | |
|                         origin.1,
 | |
|                         origin.0 + width as i32,
 | |
|                         origin.1 + height as i32,
 | |
|                         x,
 | |
|                         y,
 | |
|                         x + w,
 | |
|                         y + h
 | |
|                     ),
 | |
|                 ));
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         let mut s = Self {
 | |
|             mag_interface: MagInterface::new()?,
 | |
|             host_window: 0 as _,
 | |
|             magnifier_window: 0 as _,
 | |
|             magnifier_host_class: CString::new("ScreenCapturerWinMagnifierHost")?,
 | |
|             host_window_name: CString::new("MagnifierHost")?,
 | |
|             magnifier_window_class: CString::new("Magnifier")?,
 | |
|             magnifier_window_name: CString::new("MagnifierWindow")?,
 | |
|             rect: RECT {
 | |
|                 left: origin.0 as _,
 | |
|                 top: origin.1 as _,
 | |
|                 right: origin.0 + width as LONG,
 | |
|                 bottom: origin.1 + height as LONG,
 | |
|             },
 | |
|             width,
 | |
|             height,
 | |
|         };
 | |
| 
 | |
|         unsafe {
 | |
|             let mut instance = 0 as HMODULE;
 | |
|             if 0 == GetModuleHandleExA(
 | |
|                 GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
 | |
|                     | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
 | |
|                 DefWindowProcA as _,
 | |
|                 &mut instance as _,
 | |
|             ) {
 | |
|                 return Err(Error::new(
 | |
|                     ErrorKind::Other,
 | |
|                     format!(
 | |
|                         "Failed to GetModuleHandleExA, error {}",
 | |
|                         Error::last_os_error()
 | |
|                     ),
 | |
|                 ));
 | |
|             }
 | |
| 
 | |
|             // Register the host window class. See the MSDN documentation of the
 | |
|             // Magnification API for more information.
 | |
|             let wcex = WNDCLASSEXA {
 | |
|                 cbSize: size_of::<WNDCLASSEXA>() as _,
 | |
|                 style: 0,
 | |
|                 lpfnWndProc: Some(DefWindowProcA),
 | |
|                 cbClsExtra: 0,
 | |
|                 cbWndExtra: 0,
 | |
|                 hInstance: instance,
 | |
|                 hIcon: 0 as _,
 | |
|                 hCursor: LoadCursorA(NULL as _, IDC_ARROW as _),
 | |
|                 hbrBackground: 0 as _,
 | |
|                 lpszClassName: s.magnifier_host_class.as_ptr() as _,
 | |
|                 lpszMenuName: 0 as _,
 | |
|                 hIconSm: 0 as _,
 | |
|             };
 | |
| 
 | |
|             // Ignore the error which may happen when the class is already registered.
 | |
|             if 0 == RegisterClassExA(&wcex) {
 | |
|                 let code = GetLastError();
 | |
|                 if code != ERROR_CLASS_ALREADY_EXISTS {
 | |
|                     return Err(Error::new(
 | |
|                         ErrorKind::Other,
 | |
|                         format!(
 | |
|                             "Failed to RegisterClassExA, error {}",
 | |
|                             Error::from_raw_os_error(code as _)
 | |
|                         ),
 | |
|                     ));
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             // Create the host window.
 | |
|             s.host_window = CreateWindowExA(
 | |
|                 WS_EX_LAYERED,
 | |
|                 s.magnifier_host_class.as_ptr(),
 | |
|                 s.host_window_name.as_ptr(),
 | |
|                 WS_POPUP,
 | |
|                 0,
 | |
|                 0,
 | |
|                 0,
 | |
|                 0,
 | |
|                 NULL as _,
 | |
|                 NULL as _,
 | |
|                 instance,
 | |
|                 NULL,
 | |
|             );
 | |
|             if s.host_window.is_null() {
 | |
|                 return Err(Error::new(
 | |
|                     ErrorKind::Other,
 | |
|                     format!(
 | |
|                         "Failed to CreateWindowExA host_window, error {}",
 | |
|                         Error::last_os_error()
 | |
|                     ),
 | |
|                 ));
 | |
|             }
 | |
| 
 | |
|             // Create the magnifier control.
 | |
|             s.magnifier_window = CreateWindowExA(
 | |
|                 0,
 | |
|                 s.magnifier_window_class.as_ptr(),
 | |
|                 s.magnifier_window_name.as_ptr(),
 | |
|                 WS_CHILD | WS_VISIBLE,
 | |
|                 0,
 | |
|                 0,
 | |
|                 0,
 | |
|                 0,
 | |
|                 s.host_window,
 | |
|                 NULL as _,
 | |
|                 instance,
 | |
|                 NULL,
 | |
|             );
 | |
|             if s.magnifier_window.is_null() {
 | |
|                 return Err(Error::new(
 | |
|                     ErrorKind::Other,
 | |
|                     format!(
 | |
|                         "Failed CreateWindowA magnifier_window, error {}",
 | |
|                         Error::last_os_error()
 | |
|                     ),
 | |
|                 ));
 | |
|             }
 | |
| 
 | |
|             // Hide the host window.
 | |
|             let _ = ShowWindow(s.host_window, SW_HIDE);
 | |
| 
 | |
|             // Set the scaling callback to receive captured image.
 | |
|             if let Some(set_callback_func) = s.mag_interface.set_image_scaling_callback_func {
 | |
|                 if FALSE
 | |
|                     == set_callback_func(
 | |
|                         s.magnifier_window,
 | |
|                         Some(Self::on_gag_image_scaling_callback),
 | |
|                     )
 | |
|                 {
 | |
|                     return Err(Error::new(
 | |
|                         ErrorKind::Other,
 | |
|                         format!(
 | |
|                             "Failed to MagSetImageScalingCallback, error {}",
 | |
|                             Error::last_os_error()
 | |
|                         ),
 | |
|                     ));
 | |
|                 }
 | |
|             } else {
 | |
|                 return Err(Error::new(
 | |
|                     ErrorKind::Other,
 | |
|                     "Unreachable, set_image_scaling_callback_func should not be none",
 | |
|                 ));
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         Ok(s)
 | |
|     }
 | |
| 
 | |
|     pub(crate) fn exclude(&mut self, cls: &str, name: &str) -> Result<bool> {
 | |
|         let name_c = CString::new(name)?;
 | |
|         unsafe {
 | |
|             let mut hwnd = if cls.len() == 0 {
 | |
|                 FindWindowExA(NULL as _, NULL as _, NULL as _, name_c.as_ptr())
 | |
|             } else {
 | |
|                 let cls_c = CString::new(cls).unwrap();
 | |
|                 FindWindowExA(NULL as _, NULL as _, cls_c.as_ptr(), name_c.as_ptr())
 | |
|             };
 | |
| 
 | |
|             if hwnd.is_null() {
 | |
|                 return Ok(false);
 | |
|             }
 | |
| 
 | |
|             if let Some(set_window_filter_list_func) =
 | |
|                 self.mag_interface.set_window_filter_list_func
 | |
|             {
 | |
|                 if FALSE
 | |
|                     == set_window_filter_list_func(
 | |
|                         self.magnifier_window,
 | |
|                         MW_FILTERMODE_EXCLUDE,
 | |
|                         1,
 | |
|                         &mut hwnd,
 | |
|                     )
 | |
|                 {
 | |
|                     return Err(Error::new(
 | |
|                         ErrorKind::Other,
 | |
|                         format!(
 | |
|                             "Failed MagSetWindowFilterList for cls {} name {}, error {}",
 | |
|                             cls,
 | |
|                             name,
 | |
|                             Error::last_os_error()
 | |
|                         ),
 | |
|                     ));
 | |
|                 }
 | |
|             } else {
 | |
|                 return Err(Error::new(
 | |
|                     ErrorKind::Other,
 | |
|                     "Unreachable, MagSetWindowFilterList should not be none",
 | |
|                 ));
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         Ok(true)
 | |
|     }
 | |
| 
 | |
|     pub(crate) fn get_rect(&self) -> ((i32, i32), usize, usize) {
 | |
|         (
 | |
|             (self.rect.left as _, self.rect.top as _),
 | |
|             self.width as _,
 | |
|             self.height as _,
 | |
|         )
 | |
|     }
 | |
| 
 | |
|     fn clear_data() {
 | |
|         let mut lock = MAG_BUFFER.lock().unwrap();
 | |
|         lock.0 = false;
 | |
|         lock.1.clear();
 | |
|     }
 | |
| 
 | |
|     pub(crate) fn frame(&mut self, data: &mut Vec<u8>) -> Result<()> {
 | |
|         Self::clear_data();
 | |
| 
 | |
|         unsafe {
 | |
|             let x = GetSystemMetrics(SM_XVIRTUALSCREEN);
 | |
|             let y = GetSystemMetrics(SM_YVIRTUALSCREEN);
 | |
|             let w = GetSystemMetrics(SM_CXVIRTUALSCREEN);
 | |
|             let h = GetSystemMetrics(SM_CYVIRTUALSCREEN);
 | |
|             if !(self.rect.left >= x as i32
 | |
|                 && self.rect.top >= y as i32
 | |
|                 && self.rect.right <= (x + w) as i32
 | |
|                 && self.rect.bottom <= (y + h) as i32)
 | |
|             {
 | |
|                 return Err(Error::new(
 | |
|                     ErrorKind::Other,
 | |
|                     format!(
 | |
|                         "Failed Check screen rect ({}, {}, {} , {}) to ({}, {}, {}, {})",
 | |
|                         self.rect.left,
 | |
|                         self.rect.top,
 | |
|                         self.rect.right,
 | |
|                         self.rect.bottom,
 | |
|                         x,
 | |
|                         y,
 | |
|                         x + w,
 | |
|                         y + h
 | |
|                     ),
 | |
|                 ));
 | |
|             }
 | |
| 
 | |
|             if FALSE
 | |
|                 == SetWindowPos(
 | |
|                     self.magnifier_window,
 | |
|                     HWND_TOP,
 | |
|                     self.rect.left,
 | |
|                     self.rect.top,
 | |
|                     self.rect.right - self.rect.left,
 | |
|                     self.rect.bottom - self.rect.top,
 | |
|                     0,
 | |
|                 )
 | |
|             {
 | |
|                 return Err(Error::new(
 | |
|                     ErrorKind::Other,
 | |
|                     format!(
 | |
|                         "Failed SetWindowPos (x, y, w , h) - ({}, {}, {}, {}), error {}",
 | |
|                         self.rect.left,
 | |
|                         self.rect.top,
 | |
|                         self.rect.right - self.rect.left,
 | |
|                         self.rect.bottom - self.rect.top,
 | |
|                         Error::last_os_error()
 | |
|                     ),
 | |
|                 ));
 | |
|             }
 | |
| 
 | |
|             // on_gag_image_scaling_callback will be called and fill in the
 | |
|             // frame before set_window_source_func_ returns.
 | |
|             if let Some(set_window_source_func) = self.mag_interface.set_window_source_func {
 | |
|                 if FALSE == set_window_source_func(self.magnifier_window, self.rect) {
 | |
|                     return Err(Error::new(
 | |
|                         ErrorKind::Other,
 | |
|                         format!(
 | |
|                             "Failed to MagSetWindowSource, error {}",
 | |
|                             Error::last_os_error()
 | |
|                         ),
 | |
|                     ));
 | |
|                 }
 | |
|             } else {
 | |
|                 return Err(Error::new(
 | |
|                     ErrorKind::Other,
 | |
|                     "Unreachable, set_window_source_func should not be none",
 | |
|                 ));
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         let mut lock = MAG_BUFFER.lock().unwrap();
 | |
|         if !lock.0 {
 | |
|             return Err(Error::new(
 | |
|                 ErrorKind::Other,
 | |
|                 "No data captured by magnifier",
 | |
|             ));
 | |
|         }
 | |
| 
 | |
|         data.resize(lock.1.len(), 0);
 | |
|         unsafe {
 | |
|             std::ptr::copy_nonoverlapping(&mut lock.1[0], &mut data[0], data.len());
 | |
|         }
 | |
| 
 | |
|         Ok(())
 | |
|     }
 | |
| 
 | |
|     fn destroy_windows(&mut self) {
 | |
|         if !self.magnifier_window.is_null() {
 | |
|             unsafe {
 | |
|                 if FALSE == DestroyWindow(self.magnifier_window) {
 | |
|                     //
 | |
|                     println!(
 | |
|                         "Failed DestroyWindow magnifier window, error {}",
 | |
|                         Error::last_os_error()
 | |
|                     )
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         self.magnifier_window = NULL as _;
 | |
| 
 | |
|         if !self.host_window.is_null() {
 | |
|             unsafe {
 | |
|                 if FALSE == DestroyWindow(self.host_window) {
 | |
|                     //
 | |
|                     println!(
 | |
|                         "Failed DestroyWindow host window, error {}",
 | |
|                         Error::last_os_error()
 | |
|                     )
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         self.host_window = NULL as _;
 | |
|     }
 | |
| 
 | |
|     unsafe extern "C" fn on_gag_image_scaling_callback(
 | |
|         _hwnd: HWND,
 | |
|         srcdata: *mut ::std::os::raw::c_void,
 | |
|         srcheader: MAGIMAGEHEADER,
 | |
|         _destdata: *mut ::std::os::raw::c_void,
 | |
|         _destheader: MAGIMAGEHEADER,
 | |
|         _unclipped: RECT,
 | |
|         _clipped: RECT,
 | |
|         _dirty: HRGN,
 | |
|     ) -> BOOL {
 | |
|         Self::clear_data();
 | |
| 
 | |
|         if !IsEqualGUID(&srcheader.format, &GUID_WICPixelFormat32bppRGBA) {
 | |
|             // log warning?
 | |
|             return FALSE;
 | |
|         }
 | |
|         let mut lock = MAG_BUFFER.lock().unwrap();
 | |
|         lock.1.resize(srcheader.cbSize, 0);
 | |
|         std::ptr::copy_nonoverlapping(srcdata as _, &mut lock.1[0], srcheader.cbSize);
 | |
|         lock.0 = true;
 | |
|         TRUE
 | |
|     }
 | |
| }
 | |
| 
 | |
| #[cfg(test)]
 | |
| mod tests {
 | |
|     use super::*;
 | |
|     #[test]
 | |
|     fn test() {
 | |
|         let mut capture_mag = CapturerMag::new((0, 0), 1920, 1080).unwrap();
 | |
|         capture_mag.exclude("", "RustDeskPrivacyWindow").unwrap();
 | |
|         std::thread::sleep(std::time::Duration::from_millis(1000 * 10));
 | |
|         let mut data = Vec::new();
 | |
|         capture_mag.frame(&mut data).unwrap();
 | |
|         println!("capture data len: {}", data.len());
 | |
|     }
 | |
| }
 |