privacy_mode: win10 magnifier

Signed-off-by: fufesou <shuanglongchen@yeah.net>
This commit is contained in:
fufesou
2022-04-25 12:28:28 +08:00
parent 85cd066cd7
commit c269d1c831
37 changed files with 2163 additions and 119 deletions

View File

@@ -63,6 +63,8 @@ extern crate objc;
mod win;
#[cfg(target_os = "windows")]
pub use win::Enigo;
#[cfg(target_os = "windows")]
pub use win::ENIGO_INPUT_EXTRA_VALUE;
#[cfg(target_os = "macos")]
mod macos;

View File

@@ -2,3 +2,4 @@ mod win_impl;
pub mod keycodes;
pub use self::win_impl::Enigo;
pub use self::win_impl::ENIGO_INPUT_EXTRA_VALUE;

View File

@@ -1,7 +1,7 @@
use winapi;
use self::winapi::ctypes::c_int;
use self::winapi::shared::{minwindef::*, windef::*};
use self::winapi::shared::{basetsd::ULONG_PTR, minwindef::*, windef::*};
use self::winapi::um::winbase::*;
use self::winapi::um::winuser::*;
@@ -18,6 +18,9 @@ extern "system" {
pub struct Enigo;
static mut LAYOUT: HKL = std::ptr::null_mut();
/// The dwExtraInfo value in keyboard and mouse structure that used in SendInput()
pub const ENIGO_INPUT_EXTRA_VALUE: ULONG_PTR = 100;
fn mouse_event(flags: u32, data: u32, dx: i32, dy: i32) -> DWORD {
let mut input = INPUT {
type_: INPUT_MOUSE,
@@ -28,7 +31,7 @@ fn mouse_event(flags: u32, data: u32, dx: i32, dy: i32) -> DWORD {
mouseData: data,
dwFlags: flags,
time: 0,
dwExtraInfo: 0,
dwExtraInfo: ENIGO_INPUT_EXTRA_VALUE,
})
},
};
@@ -56,7 +59,7 @@ fn keybd_event(flags: u32, vk: u16, scan: u16) -> DWORD {
wScan: scan,
dwFlags: flags,
time: 0,
dwExtraInfo: 0,
dwExtraInfo: ENIGO_INPUT_EXTRA_VALUE,
})
},
};

View File

@@ -65,6 +65,10 @@ message LoginRequest {
message ChatMessage { string text = 1; }
message Features {
bool privacy_mode = 1;
}
message PeerInfo {
string username = 1;
string hostname = 2;
@@ -74,6 +78,7 @@ message PeerInfo {
bool sas_enabled = 6;
string version = 7;
int32 conn_id = 8;
Features features = 9;
}
message LoginResponse {
@@ -442,11 +447,6 @@ message OptionMessage {
BoolOption enable_file_transfer = 9;
}
message OptionResponse {
OptionMessage opt = 1;
string error = 2;
}
message TestDelay {
int64 time = 1;
bool from_client = 2;
@@ -469,6 +469,44 @@ message AudioFrame {
int64 timestamp = 2;
}
message BackNotification {
// no need to consider block input by someone else
enum BlockInputState {
StateUnknown = 1;
OnSucceeded = 2;
OnFailed = 3;
OffSucceeded = 4;
OffFailed = 5;
}
enum PrivacyModeState {
StateUnknown = 1;
// Privacy mode on by someone else
OnByOther = 2;
// Privacy mode is not supported on the remote side
NotSupported = 3;
// Privacy mode on by self
OnSucceeded = 4;
// Privacy mode on by self, but denied
OnFailedDenied = 5;
// Some plugins are not found
OnFailedPlugin = 6;
// Privacy mode on by self, but failed
OnFailed = 7;
// Privacy mode off by self
OffSucceeded = 8;
// Ctrl + P
OffByPeer = 9;
// Privacy mode off by self, but failed
OffFailed = 10;
OffUnknown = 11;
}
oneof union {
PrivacyModeState privacy_mode_state = 1;
BlockInputState block_input_state = 2;
}
}
message Misc {
oneof union {
ChatMessage chat_message = 4;
@@ -478,8 +516,8 @@ message Misc {
AudioFormat audio_format = 8;
string close_reason = 9;
bool refresh_video = 10;
OptionResponse option_response = 11;
bool video_received = 12;
BackNotification back_notification = 13;
}
}

View File

@@ -17,11 +17,12 @@ block = "0.1"
cfg-if = "1.0"
libc = "0.2"
num_cpus = "1.13"
lazy_static = "1.4"
[dependencies.winapi]
version = "0.3"
default-features = true
features = ["dxgi", "dxgi1_2", "dxgi1_5", "d3d11", "winuser"]
features = ["dxgi", "dxgi1_2", "dxgi1_5", "d3d11", "winuser", "winerror", "errhandlingapi", "libloaderapi"]
[target.'cfg(target_os = "android")'.dependencies]
android_logger = "0.10"

View File

@@ -0,0 +1,105 @@
extern crate repng;
extern crate scrap;
use std::fs::File;
#[cfg(windows)]
use scrap::CapturerMag;
use scrap::{i420_to_rgb, Display};
fn main() {
let n = Display::all().unwrap().len();
for i in 0..n {
#[cfg(windows)]
record(i);
}
}
fn get_display(i: usize) -> Display {
Display::all().unwrap().remove(i)
}
#[cfg(windows)]
fn record(i: usize) {
for d in Display::all().unwrap() {
println!("{:?} {} {}", d.origin(), d.width(), d.height());
}
let display = get_display(i);
let (w, h) = (display.width(), display.height());
{
let mut capture_mag =
CapturerMag::new(display.origin(), display.width(), display.height(), false)
.expect("Couldn't begin capture.");
let wnd_cls = "";
let wnd_name = "RustDeskPrivacyWindow";
if false == capture_mag.exclude(wnd_cls, wnd_name).unwrap() {
println!("No window found for cls {} name {}", wnd_cls, wnd_name);
} else {
println!("Filter window for cls {} name {}", wnd_cls, wnd_name);
}
let frame = capture_mag.frame(0).unwrap();
println!("Capture data len: {}, Saving...", frame.len());
let mut bitflipped = Vec::with_capacity(w * h * 4);
let stride = frame.len() / h;
for y in 0..h {
for x in 0..w {
let i = stride * y + 4 * x;
bitflipped.extend_from_slice(&[frame[i + 2], frame[i + 1], frame[i], 255]);
}
}
// Save the image.
let name = format!("capture_mag_{}_1.png", i);
repng::encode(
File::create(name.clone()).unwrap(),
w as u32,
h as u32,
&bitflipped,
)
.unwrap();
println!("Image saved to `{}`.", name);
}
{
let mut capture_mag =
CapturerMag::new(display.origin(), display.width(), display.height(), true)
.expect("Couldn't begin capture.");
let wnd_cls = "";
let wnd_title = "RustDeskPrivacyWindow";
if false == capture_mag.exclude(wnd_cls, wnd_title).unwrap() {
println!("No window found for cls {} title {}", wnd_cls, wnd_title);
} else {
println!("Filter window for cls {} title {}", wnd_cls, wnd_title);
}
let buffer = capture_mag.frame(0).unwrap();
println!("Capture data len: {}, Saving...", buffer.len());
let mut frame = Default::default();
i420_to_rgb(w, h, &buffer, &mut frame);
let mut bitflipped = Vec::with_capacity(w * h * 4);
let stride = frame.len() / h;
for y in 0..h {
for x in 0..w {
let i = stride * y + 3 * x;
bitflipped.extend_from_slice(&[frame[i], frame[i + 1], frame[i + 2], 255]);
}
}
let name = format!("capture_mag_{}_2.png", i);
repng::encode(
File::create(name.clone()).unwrap(),
w as u32,
h as u32,
&bitflipped,
)
.unwrap();
println!("Image saved to `{}`.", name);
}
}

View File

@@ -46,8 +46,7 @@ fn record(i: usize) {
}
}
};
println!("Captured! Saving...");
println!("Captured data len: {}, Saving...", buffer.len());
// Flip the BGRA image into a RGBA image.
@@ -96,8 +95,7 @@ fn record(i: usize) {
}
}
};
println!("Captured! Saving...");
println!("Captured data len: {}, Saving...", buffer.len());
let mut frame = Default::default();
i420_to_rgb(w, h, &buffer, &mut frame);

View File

@@ -111,3 +111,32 @@ impl Display {
self.origin() == (0, 0)
}
}
pub struct CapturerMag {
inner: dxgi::mag::CapturerMag,
data: Vec<u8>,
}
impl CapturerMag {
pub fn is_supported() -> bool {
dxgi::mag::CapturerMag::is_supported()
}
pub fn new(origin: (i32, i32), width: usize, height: usize, use_yuv: bool) -> io::Result<Self> {
Ok(CapturerMag {
inner: dxgi::mag::CapturerMag::new(origin, width, height, use_yuv)?,
data: Vec::new(),
})
}
pub fn exclude(&mut self, cls: &str, name: &str) -> io::Result<bool> {
self.inner.exclude(cls, name)
}
// ((x, y), w, h)
pub fn get_rect(&self) -> ((i32, i32), usize, usize) {
self.inner.get_rect()
}
pub fn frame<'a>(&'a mut self, _timeout_ms: u32) -> io::Result<Frame<'a>> {
self.inner.frame(&mut self.data)?;
Ok(Frame(&self.data))
}
}

626
libs/scrap/src/dxgi/mag.rs Normal file
View File

@@ -0,0 +1,626 @@
// 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 {
if GetSystemMetrics(SM_CMONITORS) != 1 {
// Do not try to use the magnifier in multi-screen setup (where the API
// crashes sometimes).
return Err(Error::new(
ErrorKind::Other,
"Magnifier capturer cannot work on multi-screen system.",
));
}
// load lib
let lib_file_name = "Magnification.dll";
let lib_file_name_c = CString::new(lib_file_name).unwrap();
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,
GetLastError()
),
));
};
// 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: {}", GetLastError()),
));
} 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).unwrap();
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,
GetLastError()
),
));
}
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 {}", GetLastError())
}
}
}
if !self.lib_handle.is_null() {
unsafe {
if FALSE == FreeLibrary(self.lib_handle) {
println!("Failed FreeLibrary {}", GetLastError())
}
}
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,
use_yuv: bool,
data: Vec<u8>,
}
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,
use_yuv: bool,
) -> Result<Self> {
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,
use_yuv,
data: Vec::new(),
};
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: {}", GetLastError()),
));
}
// Register the host window class. See the MSDN documentation of the
// Magnification API for more infomation.
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: {}", code),
));
}
}
// 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: {}",
GetLastError()
),
));
}
// 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: {}",
GetLastError()
),
));
}
// 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: {}",
GetLastError()
),
));
}
} 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).unwrap();
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 {}, err: {}",
cls,
name,
GetLastError()
),
));
}
} 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);
self.rect = RECT {
left: x as _,
top: y as _,
right: (x + w) as _,
bottom: (y + h) as _,
};
if FALSE
== SetWindowPos(
self.magnifier_window,
HWND_TOP,
self.rect.left,
self.rect.top,
self.rect.right,
self.rect.bottom,
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.bottom,
GetLastError()
),
));
}
// 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: {}", GetLastError()),
));
}
} 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",
));
}
if self.use_yuv {
self.data.resize(lock.1.len(), 0);
unsafe {
std::ptr::copy_nonoverlapping(&mut lock.1[0], &mut self.data[0], self.data.len());
}
crate::common::bgra_to_i420(
self.width as usize,
self.height as usize,
&self.data,
data,
);
} else {
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 {}", GetLastError())
}
}
}
self.magnifier_window = NULL as _;
if !self.host_window.is_null() {
unsafe {
if FALSE == DestroyWindow(self.host_window) {
//
println!("Failed DestroyWindow host window {}", GetLastError())
}
}
}
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, false).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());
}
}

View File

@@ -1,6 +1,7 @@
use std::{io, mem, ptr, slice};
pub mod gdi;
pub use gdi::CapturerGDI;
pub mod mag;
use winapi::{
shared::{